From 1613c621e19416754beda19879d574cd149bf91e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 10:18:42 +0200 Subject: mt76x2: move mt76x2 source files to mt76x2 folder Move mt76x2 and mt76x2u drivers to mt76x2 subfolder and leave just shared code in mt76 root folder Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 43 +- drivers/net/wireless/mediatek/mt76/Makefile | 22 +- drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig | 20 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 210 ----- drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig | 20 + drivers/net/wireless/mediatek/mt76/mt76x2/Makefile | 18 + drivers/net/wireless/mediatek/mt76/mt76x2/common.c | 42 + .../net/wireless/mediatek/mt76/mt76x2/debugfs.c | 137 ++++ drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h | 146 ++++ drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c | 531 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h | 73 ++ drivers/net/wireless/mediatek/mt76/mt76x2/init.c | 219 +++++ drivers/net/wireless/mediatek/mt76/mt76x2/mac.c | 239 ++++++ drivers/net/wireless/mediatek/mt76/mt76x2/mac.h | 64 ++ drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c | 125 +++ drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h | 101 +++ drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 210 +++++ .../net/wireless/mediatek/mt76/mt76x2/mt76x2u.h | 65 ++ drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 111 +++ .../net/wireless/mediatek/mt76/mt76x2/pci_core.c | 76 ++ .../net/wireless/mediatek/mt76/mt76x2/pci_dfs.c | 878 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_dma.c | 39 + .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 541 +++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_mac.c | 272 +++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 311 ++++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_mcu.c | 189 +++++ .../net/wireless/mediatek/mt76/mt76x2/pci_phy.c | 458 +++++++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_trace.c | 23 + drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c | 175 ++++ drivers/net/wireless/mediatek/mt76/mt76x2/phy.c | 344 ++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/trace.h | 144 ++++ drivers/net/wireless/mediatek/mt76/mt76x2/tx.c | 118 +++ drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 153 ++++ .../net/wireless/mediatek/mt76/mt76x2/usb_core.c | 53 ++ .../net/wireless/mediatek/mt76/mt76x2/usb_init.c | 310 ++++++++ .../net/wireless/mediatek/mt76/mt76x2/usb_mac.c | 222 ++++++ .../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 180 +++++ .../net/wireless/mediatek/mt76/mt76x2/usb_mcu.c | 292 +++++++ .../net/wireless/mediatek/mt76/mt76x2/usb_phy.c | 231 ++++++ drivers/net/wireless/mediatek/mt76/mt76x2_common.c | 42 - drivers/net/wireless/mediatek/mt76/mt76x2_core.c | 76 -- .../net/wireless/mediatek/mt76/mt76x2_debugfs.c | 137 ---- drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c | 878 --------------------- drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h | 146 ---- drivers/net/wireless/mediatek/mt76/mt76x2_dma.c | 39 - drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c | 531 ------------- drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h | 73 -- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 541 ------------- .../wireless/mediatek/mt76/mt76x2_init_common.c | 219 ----- drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 272 ------- drivers/net/wireless/mediatek/mt76/mt76x2_mac.h | 64 -- .../net/wireless/mediatek/mt76/mt76x2_mac_common.c | 239 ------ drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 311 -------- drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c | 189 ----- drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h | 101 --- .../net/wireless/mediatek/mt76/mt76x2_mcu_common.c | 125 --- drivers/net/wireless/mediatek/mt76/mt76x2_pci.c | 111 --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 458 ----------- .../net/wireless/mediatek/mt76/mt76x2_phy_common.c | 344 -------- drivers/net/wireless/mediatek/mt76/mt76x2_trace.c | 23 - drivers/net/wireless/mediatek/mt76/mt76x2_trace.h | 144 ---- drivers/net/wireless/mediatek/mt76/mt76x2_tx.c | 175 ---- .../net/wireless/mediatek/mt76/mt76x2_tx_common.c | 118 --- drivers/net/wireless/mediatek/mt76/mt76x2_usb.c | 153 ---- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 65 -- drivers/net/wireless/mediatek/mt76/mt76x2u_core.c | 53 -- drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 310 -------- drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c | 222 ------ drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | 180 ----- drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c | 292 ------- drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c | 231 ------ 71 files changed, 7134 insertions(+), 7133 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/Makefile create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/common.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mac.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/phy.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/trace.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/tx.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_core.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_dma.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_init.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mac.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mac.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_main.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_pci.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_phy.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_trace.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_trace.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_tx.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_usb.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_core.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_init.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_main.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 7f24aad94efd..0ccbcd7e887d 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -13,44 +13,5 @@ config MT76x02_USB tristate select MT76_USB -config MT76x0_COMMON - tristate - select MT76x02_LIB - -config MT76x2_COMMON - tristate - select MT76x02_LIB - -config MT76x0U - tristate "MediaTek MT76x0U (USB) support" - select MT76x0_COMMON - select MT76x02_USB - depends on MAC80211 - depends on USB - help - This adds support for MT7610U-based wireless USB dongles. - -config MT76x0E - tristate "MediaTek MT76x0E (PCIe) support" - select MT76x0_COMMON - depends on MAC80211 - depends on PCI - help - This adds support for MT7610/MT7630-based wireless PCIe devices. - -config MT76x2E - tristate "MediaTek MT76x2E (PCIe) support" - select MT76x2_COMMON - depends on MAC80211 - depends on PCI - ---help--- - This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices. - -config MT76x2U - tristate "MediaTek MT76x2U (USB) support" - select MT76x2_COMMON - select MT76x02_USB - depends on MAC80211 - depends on USB - help - This adds support for MT7612U-based wireless USB dongles. +source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 2346a1b768bc..907b9e2d7044 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,11 +1,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o -obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o -obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o -obj-$(CONFIG_MT76x2E) += mt76x2e.o -obj-$(CONFIG_MT76x2U) += mt76x2u.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o agg-rx.o @@ -20,19 +16,5 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o -mt76x2-common-y := \ - mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ - mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \ - mt76x2_debugfs.o mt76x2_mcu_common.o - -mt76x2e-y := \ - mt76x2_pci.o mt76x2_dma.o \ - mt76x2_main.o mt76x2_init.o mt76x2_tx.o \ - mt76x2_core.o mt76x2_mac.o mt76x2_mcu.o mt76x2_phy.o \ - mt76x2_dfs.o mt76x2_trace.o - -mt76x2u-y := \ - mt76x2_usb.o mt76x2u_init.o mt76x2u_main.o mt76x2u_mac.o \ - mt76x2u_mcu.o mt76x2u_phy.o mt76x2u_core.o - -CFLAGS_mt76x2_trace.o := -I$(src) +obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ +obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig new file mode 100644 index 000000000000..9a6157db3893 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig @@ -0,0 +1,20 @@ +config MT76x0_COMMON + tristate + select MT76x02_LIB + +config MT76x0U + tristate "MediaTek MT76x0U (USB) support" + select MT76x0_COMMON + select MT76x02_USB + depends on MAC80211 + depends on USB + help + This adds support for MT7610U-based wireless USB dongles. + +config MT76x0E + tristate "MediaTek MT76x0E (PCIe) support" + select MT76x0_COMMON + depends on MAC80211 + depends on PCI + help + This adds support for MT7610/MT7630-based wireless PCIe devices. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h deleted file mode 100644 index d6ccab06a594..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 __MT76x2_H -#define __MT76x2_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MT7662_FIRMWARE "mt7662.bin" -#define MT7662_ROM_PATCH "mt7662_rom_patch.bin" -#define MT7662_EEPROM_SIZE 512 - -#define MT7662U_FIRMWARE "mediatek/mt7662u.bin" -#define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin" - -#define MT_MAX_CHAINS 2 - -#define MT_CALIBRATE_INTERVAL HZ - -#include "mt76.h" -#include "mt76x02_regs.h" -#include "mt76x2_mac.h" -#include "mt76x2_dfs.h" - -struct mt76x2_rx_freq_cal { - s8 high_gain[MT_MAX_CHAINS]; - s8 rssi_offset[MT_MAX_CHAINS]; - s8 lna_gain; - u32 mcu_gain; -}; - -struct mt76x2_calibration { - struct mt76x2_rx_freq_cal rx; - - u8 agc_gain_init[MT_MAX_CHAINS]; - u8 agc_gain_cur[MT_MAX_CHAINS]; - - u16 false_cca; - s8 avg_rssi_all; - s8 agc_gain_adjust; - s8 low_gain; - - u8 temp; - - bool init_cal_done; - bool tssi_cal_done; - bool tssi_comp_pending; - bool dpd_cal_done; - bool channel_cal_done; -}; - -struct mt76x2_dev { - struct mt76_dev mt76; /* must be first */ - - struct mac_address macaddr_list[8]; - - struct mutex mutex; - - u8 txdone_seq; - DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); - - struct sk_buff *rx_head; - - struct tasklet_struct tx_tasklet; - struct tasklet_struct pre_tbtt_tasklet; - struct delayed_work cal_work; - struct delayed_work mac_work; - - u32 aggr_stats[32]; - - struct sk_buff *beacons[8]; - u8 beacon_mask; - u8 beacon_data_mask; - - u8 tbtt_count; - u16 beacon_int; - - struct mt76x2_calibration cal; - - s8 target_power; - s8 target_power_delta[2]; - bool enable_tpc; - - u8 coverage_class; - u8 slottime; - - struct mt76x2_dfs_pattern_detector dfs_pd; -}; - -static inline bool is_mt7612(struct mt76x2_dev *dev) -{ - return mt76_chip(&dev->mt76) == 0x7612; -} - -static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - - return ((chan->flags & IEEE80211_CHAN_RADAR) && - chan->dfs_state != NL80211_DFS_AVAILABLE); -} - -extern const struct ieee80211_ops mt76x2_ops; - -struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); -int mt76x2_register_device(struct mt76x2_dev *dev); -void mt76x2_init_debugfs(struct mt76x2_dev *dev); -void mt76x2_init_device(struct mt76x2_dev *dev); - -irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance); -void mt76x2_phy_power_on(struct mt76x2_dev *dev); -int mt76x2_init_hardware(struct mt76x2_dev *dev); -void mt76x2_stop_hardware(struct mt76x2_dev *dev); -int mt76x2_eeprom_init(struct mt76x2_dev *dev); -int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel); -void mt76x2_set_tx_ackto(struct mt76x2_dev *dev); - -void mt76x2_phy_set_antenna(struct mt76x2_dev *dev); -int mt76x2_phy_start(struct mt76x2_dev *dev); -int mt76x2_phy_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef); -int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain); -void mt76x2_phy_calibrate(struct work_struct *work); -void mt76x2_phy_set_txpower(struct mt76x2_dev *dev); - -int mt76x2_mcu_init(struct mt76x2_dev *dev); -int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, - u8 bw_index, bool scan); -int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, - u8 channel); - -void mt76x2_tx_tasklet(unsigned long data); -void mt76x2_dma_cleanup(struct mt76x2_dev *dev); - -void mt76x2_cleanup(struct mt76x2_dev *dev); - -void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb); -int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info); -void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush); -void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val); - -void mt76x2_pre_tbtt_tasklet(unsigned long arg); - -void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); -void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb); - -void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); - -void mt76x2_update_channel(struct mt76_dev *mdev); - -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate); -s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); -void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); - - -void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); -void mt76x2_init_txpower(struct mt76x2_dev *dev, - struct ieee80211_supported_band *sband); -void mt76_write_mac_initvals(struct mt76x2_dev *dev); - -int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void mt76x2_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); -void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); - -void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait); -void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, - enum nl80211_band band); -void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, - enum nl80211_band band, u8 bw); -void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl); -void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper); -int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev); -void mt76x2_apply_gain_adj(struct mt76x2_dev *dev); - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig new file mode 100644 index 000000000000..2b414a0e9088 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig @@ -0,0 +1,20 @@ +config MT76x2_COMMON + tristate + select MT76x02_LIB + +config MT76x2E + tristate "MediaTek MT76x2E (PCIe) support" + select MT76x2_COMMON + depends on MAC80211 + depends on PCI + ---help--- + This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices. + +config MT76x2U + tristate "MediaTek MT76x2U (USB) support" + select MT76x2_COMMON + select MT76x02_USB + depends on MAC80211 + depends on USB + help + This adds support for MT7612U-based wireless USB dongles. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile new file mode 100644 index 000000000000..2b5a3164274e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -0,0 +1,18 @@ +obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o +obj-$(CONFIG_MT76x2E) += mt76x2e.o +obj-$(CONFIG_MT76x2U) += mt76x2u.o + +mt76x2-common-y := \ + eeprom.o tx.o mac.o init.o common.o phy.o \ + debugfs.o mcu.o + +mt76x2e-y := \ + pci.o pci_dma.o pci_main.o pci_init.o pci_tx.o \ + pci_core.o pci_mac.o pci_mcu.o pci_phy.o \ + pci_dfs.o pci_trace.o + +mt76x2u-y := \ + usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \ + usb_phy.o usb_core.o + +CFLAGS_pci_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c new file mode 100644 index 000000000000..fa6bad3bf613 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "../mt76x02_mac.h" + +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + void *rxwi = skb->data; + + if (q == MT_RXQ_MCU) { + /* this is used just by mmio code */ + skb_queue_tail(&mdev->mmio.mcu.res_q, skb); + wake_up(&mdev->mmio.mcu.wait); + return; + } + + skb_pull(skb, sizeof(struct mt76x02_rxwi)); + if (mt76x2_mac_process_rx(dev, skb, rxwi)) { + dev_kfree_skb(skb); + return; + } + + mt76_rx(&dev->mt76, q, skb); +} +EXPORT_SYMBOL_GPL(mt76x2_queue_rx_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c new file mode 100644 index 000000000000..ea373bae1522 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include "mt76x2.h" + +static int +mt76x2_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = file->private; + int i, j; + + for (i = 0; i < 4; i++) { + seq_puts(file, "Length: "); + for (j = 0; j < 8; j++) + seq_printf(file, "%8d | ", i * 8 + j + 1); + seq_puts(file, "\n"); + seq_puts(file, "Count: "); + for (j = 0; j < 8; j++) + seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); + seq_puts(file, "\n"); + seq_puts(file, "--------"); + for (j = 0; j < 8; j++) + seq_puts(file, "-----------"); + seq_puts(file, "\n"); + } + + return 0; +} + +static int +mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt76x2_ampdu_stat_read, inode->i_private); +} + +static int read_txpower(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = dev_get_drvdata(file->private); + + seq_printf(file, "Target power: %d\n", dev->target_power); + + mt76_seq_puts_array(file, "Delta", dev->target_power_delta, + ARRAY_SIZE(dev->target_power_delta)); + return 0; +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt76x2_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int +mt76x2_dfs_stat_read(struct seq_file *file, void *data) +{ + int i; + struct mt76x2_dev *dev = file->private; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + seq_printf(file, "allocated sequences:\t%d\n", + dfs_pd->seq_stats.seq_pool_len); + seq_printf(file, "used sequences:\t\t%d\n", + dfs_pd->seq_stats.seq_len); + seq_puts(file, "\n"); + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + seq_printf(file, "engine: %d\n", i); + seq_printf(file, " hw pattern detected:\t%d\n", + dfs_pd->stats[i].hw_pattern); + seq_printf(file, " hw pulse discarded:\t%d\n", + dfs_pd->stats[i].hw_pulse_discarded); + seq_printf(file, " sw pattern detected:\t%d\n", + dfs_pd->stats[i].sw_pattern); + } + + return 0; +} + +static int +mt76x2_dfs_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt76x2_dfs_stat_read, inode->i_private); +} + +static const struct file_operations fops_dfs_stat = { + .open = mt76x2_dfs_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int read_agc(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = dev_get_drvdata(file->private); + + seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); + seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); + seq_printf(file, "false_cca: %d\n", dev->cal.false_cca); + seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust); + + return 0; +} + +void mt76x2_init_debugfs(struct mt76x2_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return; + + debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); + debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); + + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); + debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, + read_txpower); + + debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); +} +EXPORT_SYMBOL_GPL(mt76x2_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h new file mode 100644 index 000000000000..693f421bf096 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 Lorenzo Bianconi + * + * 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 __MT76x2_DFS_H +#define __MT76x2_DFS_H + +#include +#include + +#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ +#define MT_DFS_NUM_ENGINES 4 + +/* bbp params */ +#define MT_DFS_SYM_ROUND 0 +#define MT_DFS_DELTA_DELAY 2 +#define MT_DFS_VGA_MASK 0 +#define MT_DFS_PWR_GAIN_OFFSET 3 +#define MT_DFS_PWR_DOWN_TIME 0xf +#define MT_DFS_RX_PE_MASK 0xff +#define MT_DFS_PKT_END_MASK 0 +#define MT_DFS_CH_EN 0xf + +/* sw detector params */ +#define MT_DFS_EVENT_LOOP 64 +#define MT_DFS_SW_TIMEOUT (HZ / 20) +#define MT_DFS_EVENT_WINDOW (HZ / 5) +#define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) +#define MT_DFS_EVENT_TIME_MARGIN 2000 +#define MT_DFS_PRI_MARGIN 4 +#define MT_DFS_SEQUENCE_TH 6 + +#define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) +#define MT_DFS_FCC_MIN_PRI (3000 - 2) +#define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) +#define MT_DFS_JP_MIN_PRI (28500 - 2) +#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) +#define MT_DFS_ETSI_MIN_PRI (4500 - 20) + +struct mt76x2_radar_specs { + u8 mode; + u16 avg_len; + u16 e_low; + u16 e_high; + u16 w_low; + u16 w_high; + u16 w_margin; + u32 t_low; + u32 t_high; + u16 t_margin; + u32 b_low; + u32 b_high; + u32 event_expiration; + u16 pwr_jmp; +}; + +#define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) +#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) +#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) +#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) +struct mt76x2_dfs_event { + unsigned long fetch_ts; + u32 ts; + u16 width; + u8 engine; +}; + +#define MT_DFS_EVENT_BUFLEN 256 +struct mt76x2_dfs_event_rb { + struct mt76x2_dfs_event data[MT_DFS_EVENT_BUFLEN]; + int h_rb, t_rb; +}; + +struct mt76x2_dfs_sequence { + struct list_head head; + u32 first_ts; + u32 last_ts; + u32 pri; + u16 count; + u8 engine; +}; + +struct mt76x2_dfs_hw_pulse { + u8 engine; + u32 period; + u32 w1; + u32 w2; + u32 burst; +}; + +struct mt76x2_dfs_sw_detector_params { + u32 min_pri; + u32 max_pri; + u32 pri_margin; +}; + +struct mt76x2_dfs_engine_stats { + u32 hw_pattern; + u32 hw_pulse_discarded; + u32 sw_pattern; +}; + +struct mt76x2_dfs_seq_stats { + u32 seq_pool_len; + u32 seq_len; +}; + +struct mt76x2_dfs_pattern_detector { + enum nl80211_dfs_regions region; + + u8 chirp_pulse_cnt; + u32 chirp_pulse_ts; + + struct mt76x2_dfs_sw_detector_params sw_dpd_params; + struct mt76x2_dfs_event_rb event_rb[2]; + + struct list_head sequences; + struct list_head seq_pool; + struct mt76x2_dfs_seq_stats seq_stats; + + unsigned long last_sw_check; + u32 last_event_ts; + + struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; + struct tasklet_struct dfs_tasklet; +}; + +void mt76x2_dfs_init_params(struct mt76x2_dev *dev); +void mt76x2_dfs_init_detector(struct mt76x2_dev *dev); +void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev); +void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, + enum nl80211_dfs_regions region); + +#endif /* __MT76x2_DFS_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c new file mode 100644 index 000000000000..55eda67f0e79 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include +#include "mt76x2.h" +#include "eeprom.h" + +#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 + +static int +mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, + void *dest, int len) +{ + if (field + len > dev->mt76.eeprom.size) + return -1; + + memcpy(dest, dev->mt76.eeprom.data + field, len); + return 0; +} + +static int +mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) +{ + void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; + + memcpy(dev->mt76.macaddr, src, ETH_ALEN); + return 0; +} + +static bool +mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +{ + u16 *efuse_w = (u16 *) efuse; + + if (efuse_w[MT_EE_NIC_CONF_0] != 0) + return false; + + if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) + return false; + + if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) + return false; + + return true; +} + +static void +mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +{ +#define GROUP_5G(_id) \ + MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ + MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ + MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ + MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 + + static const u8 cal_free_bytes[] = { + MT_EE_XTAL_TRIM_1, + MT_EE_TX_POWER_EXT_PA_5G + 1, + MT_EE_TX_POWER_0_START_2G, + MT_EE_TX_POWER_0_START_2G + 1, + MT_EE_TX_POWER_1_START_2G, + MT_EE_TX_POWER_1_START_2G + 1, + GROUP_5G(0), + GROUP_5G(1), + GROUP_5G(2), + GROUP_5G(3), + GROUP_5G(4), + GROUP_5G(5), + MT_EE_RF_2G_TSSI_OFF_TXPOWER, + MT_EE_RF_2G_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, + }; + u8 *eeprom = dev->mt76.eeprom.data; + u8 prev_grp0[4] = { + eeprom[MT_EE_TX_POWER_0_START_5G], + eeprom[MT_EE_TX_POWER_0_START_5G + 1], + eeprom[MT_EE_TX_POWER_1_START_5G], + eeprom[MT_EE_TX_POWER_1_START_5G + 1] + }; + u16 val; + int i; + + if (!mt76x2_has_cal_free_data(dev, efuse)) + return; + + for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { + int offset = cal_free_bytes[i]; + + eeprom[offset] = efuse[offset]; + } + + if (!(efuse[MT_EE_TX_POWER_0_START_5G] | + efuse[MT_EE_TX_POWER_0_START_5G + 1])) + memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); + if (!(efuse[MT_EE_TX_POWER_1_START_5G] | + efuse[MT_EE_TX_POWER_1_START_5G + 1])) + memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); + + val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); + if (val != 0xffff) + eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; + + val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); + if (val != 0xffff) + eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; + + val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); + if (val != 0xffff) + eeprom[MT_EE_BT_PMUCFG] = val & 0xff; +} + +static int mt76x2_check_eeprom(struct mt76x2_dev *dev) +{ + u16 val = get_unaligned_le16(dev->mt76.eeprom.data); + + if (!val) + val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); + + switch (val) { + case 0x7662: + case 0x7612: + return 0; + default: + dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); + return -EINVAL; + } +} + +static int +mt76x2_eeprom_load(struct mt76x2_dev *dev) +{ + void *efuse; + bool found; + int ret; + + ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); + if (ret < 0) + return ret; + + found = ret; + if (found) + found = !mt76x2_check_eeprom(dev); + + dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, + GFP_KERNEL); + dev->mt76.otp.size = MT7662_EEPROM_SIZE; + if (!dev->mt76.otp.data) + return -ENOMEM; + + efuse = dev->mt76.otp.data; + + if (mt76x02_get_efuse_data(&dev->mt76, 0, efuse, + MT7662_EEPROM_SIZE, MT_EE_READ)) + goto out; + + if (found) { + mt76x2_apply_cal_free_data(dev, efuse); + } else { + /* FIXME: check if efuse data is complete */ + found = true; + memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); + } + +out: + if (!found) + return -ENOENT; + + return 0; +} + +static void +mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) +{ + s8 *dest = dev->cal.rx.high_gain; + + if (!mt76x02_field_valid(val)) { + dest[0] = 0; + dest[1] = 0; + return; + } + + dest[0] = mt76x02_sign_extend(val, 4); + dest[1] = mt76x02_sign_extend(val >> 4, 4); +} + +static void +mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) +{ + s8 *dest = dev->cal.rx.rssi_offset; + + if (!mt76x02_field_valid(val)) { + dest[chain] = 0; + return; + } + + dest[chain] = mt76x02_sign_extend_optional(val, 7); +} + +static enum mt76x2_cal_channel_group +mt76x2_get_cal_channel_group(int channel) +{ + if (channel >= 184 && channel <= 196) + return MT_CH_5G_JAPAN; + if (channel <= 48) + return MT_CH_5G_UNII_1; + if (channel <= 64) + return MT_CH_5G_UNII_2; + if (channel <= 114) + return MT_CH_5G_UNII_2E_1; + if (channel <= 144) + return MT_CH_5G_UNII_2E_2; + return MT_CH_5G_UNII_3; +} + +static u8 +mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) +{ + enum mt76x2_cal_channel_group group; + + group = mt76x2_get_cal_channel_group(channel); + switch (group) { + case MT_CH_5G_JAPAN: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); + case MT_CH_5G_UNII_1: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; + case MT_CH_5G_UNII_2: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); + case MT_CH_5G_UNII_2E_1: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; + case MT_CH_5G_UNII_2E_2: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); + default: + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; + } +} + +void mt76x2_read_rx_gain(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + int channel = chan->hw_value; + s8 lna_5g[3], lna_2g; + u8 lna; + u16 val; + + if (chan->band == NL80211_BAND_2GHZ) + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; + else + val = mt76x2_get_5g_rx_gain(dev, channel); + + mt76x2_set_rx_gain_group(dev, val); + + mt76x02_get_rx_gain(&dev->mt76, chan->band, &val, &lna_2g, lna_5g); + mt76x2_set_rssi_offset(dev, 0, val); + mt76x2_set_rssi_offset(dev, 1, val >> 8); + + dev->cal.rx.mcu_gain = (lna_2g & 0xff); + dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; + dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; + dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; + + lna = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan); + dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); +} +EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); + +void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, + struct ieee80211_channel *chan) +{ + bool is_5ghz; + u16 val; + + is_5ghz = chan->band == NL80211_BAND_5GHZ; + + memset(t, 0, sizeof(*t)); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK); + t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); + t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); + + if (is_5ghz) + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_5G_6M); + else + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_2G_6M); + t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); + t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); + + if (is_5ghz) + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_5G_24M); + else + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_2G_24M); + t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); + t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0); + t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); + t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4); + t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); + t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8); + t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); + t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12); + t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); + t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0); + t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val); + t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4); + t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val); + t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8); + if (!is_5ghz) + val >>= 8; + t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8); + + memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8); + t->stbc[8] = t->vht[8]; + t->stbc[9] = t->vht[9]; +} +EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); + +static void +mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan, int chain, int offset) +{ + int channel = chan->hw_value; + int delta_idx; + u8 data[6]; + u16 val; + + if (channel < 6) + delta_idx = 3; + else if (channel < 11) + delta_idx = 4; + else + delta_idx = 5; + + mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); + + t->chain[chain].tssi_slope = data[0]; + t->chain[chain].tssi_offset = data[1]; + t->chain[chain].target_power = data[2]; + t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER); + t->target_power = val >> 8; +} + +static void +mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan, int chain, int offset) +{ + int channel = chan->hw_value; + enum mt76x2_cal_channel_group group; + int delta_idx; + u16 val; + u8 data[5]; + + group = mt76x2_get_cal_channel_group(channel); + offset += group * MT_TX_POWER_GROUP_SIZE_5G; + + if (channel >= 192) + delta_idx = 4; + else if (channel >= 184) + delta_idx = 3; + else if (channel < 44) + delta_idx = 3; + else if (channel < 52) + delta_idx = 4; + else if (channel < 58) + delta_idx = 3; + else if (channel < 98) + delta_idx = 4; + else if (channel < 106) + delta_idx = 3; + else if (channel < 116) + delta_idx = 4; + else if (channel < 130) + delta_idx = 3; + else if (channel < 149) + delta_idx = 4; + else if (channel < 157) + delta_idx = 3; + else + delta_idx = 4; + + mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); + + t->chain[chain].tssi_slope = data[0]; + t->chain[chain].tssi_offset = data[1]; + t->chain[chain].target_power = data[2]; + t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN); + t->target_power = val & 0xff; +} + +void mt76x2_get_power_info(struct mt76x2_dev *dev, + struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan) +{ + u16 bw40, bw80; + + memset(t, 0, sizeof(*t)); + + bw40 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW40); + bw80 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW80); + + if (chan->band == NL80211_BAND_5GHZ) { + bw40 >>= 8; + mt76x2_get_power_info_5g(dev, t, chan, 0, + MT_EE_TX_POWER_0_START_5G); + mt76x2_get_power_info_5g(dev, t, chan, 1, + MT_EE_TX_POWER_1_START_5G); + } else { + mt76x2_get_power_info_2g(dev, t, chan, 0, + MT_EE_TX_POWER_0_START_2G); + mt76x2_get_power_info_2g(dev, t, chan, 1, + MT_EE_TX_POWER_1_START_2G); + } + + if (mt76x02_tssi_enabled(&dev->mt76) || + !mt76x02_field_valid(t->target_power)) + t->target_power = t->chain[0].target_power; + + t->delta_bw40 = mt76x02_rate_power_val(bw40); + t->delta_bw80 = mt76x02_rate_power_val(bw80); +} +EXPORT_SYMBOL_GPL(mt76x2_get_power_info); + +int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) +{ + enum nl80211_band band = dev->mt76.chandef.chan->band; + u16 val, slope; + u8 bounds; + + memset(t, 0, sizeof(*t)); + + if (!mt76x02_temp_tx_alc_enabled(&dev->mt76)) + return -EINVAL; + + if (!mt76x02_ext_pa_enabled(&dev->mt76, band)) + return -EINVAL; + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8; + t->temp_25_ref = val & 0x7f; + if (band == NL80211_BAND_5GHZ) { + slope = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_TEMP_COMP_SLOPE_5G); + bounds = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_EXT_PA_5G); + } else { + slope = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_TEMP_COMP_SLOPE_2G); + bounds = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_DELTA_BW80) >> 8; + } + + t->high_slope = slope & 0xff; + t->low_slope = slope >> 8; + t->lower_bound = 0 - (bounds & 0xf); + t->upper_bound = (bounds >> 4) & 0xf; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); + +int mt76x2_eeprom_init(struct mt76x2_dev *dev) +{ + int ret; + + ret = mt76x2_eeprom_load(dev); + if (ret) + return ret; + + mt76x02_eeprom_parse_hw_cap(&dev->mt76); + mt76x2_eeprom_get_macaddr(dev); + mt76_eeprom_override(&dev->mt76); + dev->mt76.macaddr[0] &= ~BIT(1); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x2_eeprom_init); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h new file mode 100644 index 000000000000..33277c7bca9c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 __MT76x2_EEPROM_H +#define __MT76x2_EEPROM_H + +#include "../mt76x02_eeprom.h" + +enum mt76x2_cal_channel_group { + MT_CH_5G_JAPAN, + MT_CH_5G_UNII_1, + MT_CH_5G_UNII_2, + MT_CH_5G_UNII_2E_1, + MT_CH_5G_UNII_2E_2, + MT_CH_5G_UNII_3, + __MT_CH_MAX +}; + +struct mt76x2_tx_power_info { + u8 target_power; + + s8 delta_bw40; + s8 delta_bw80; + + struct { + s8 tssi_slope; + s8 tssi_offset; + s8 target_power; + s8 delta; + } chain[MT_MAX_CHAINS]; +}; + +struct mt76x2_temp_comp { + u8 temp_25_ref; + int lower_bound; /* J */ + int upper_bound; /* J */ + unsigned int high_slope; /* J / dB */ + unsigned int low_slope; /* J / dB */ +}; + +void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, + struct ieee80211_channel *chan); +void mt76x2_get_power_info(struct mt76x2_dev *dev, + struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan); +int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); +void mt76x2_read_rx_gain(struct mt76x2_dev *dev); + +static inline bool +mt76x2_has_ext_lna(struct mt76x2_dev *dev) +{ + u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); + + if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) + return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; + else + return val & MT_EE_NIC_CONF_1_LNA_EXT_5G; +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c new file mode 100644 index 000000000000..d672771963d5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "eeprom.h" +#include "../mt76x02_phy.h" + +static void +mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) +{ + u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL); + + if (enable) + val |= (MT_WLAN_FUN_CTRL_WLAN_EN | + MT_WLAN_FUN_CTRL_WLAN_CLK_EN); + else + val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN | + MT_WLAN_FUN_CTRL_WLAN_CLK_EN); + + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); +} + +void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) +{ + u32 val; + + if (!enable) + goto out; + + val = mt76_rr(dev, MT_WLAN_FUN_CTRL); + + val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; + + if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { + val |= MT_WLAN_FUN_CTRL_WLAN_RESET_RF; + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + val &= ~MT_WLAN_FUN_CTRL_WLAN_RESET_RF; + } + + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + +out: + mt76x2_set_wlan_state(dev, enable); +} +EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); + +void mt76_write_mac_initvals(struct mt76x2_dev *dev) +{ +#define DEFAULT_PROT_CFG_CCK \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x3) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ + MT_PROT_CFG_RTS_THRESH) + +#define DEFAULT_PROT_CFG_OFDM \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ + MT_PROT_CFG_RTS_THRESH) + +#define DEFAULT_PROT_CFG_20 \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ + FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x17)) + +#define DEFAULT_PROT_CFG_40 \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2084) | \ + FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f)) + + static const struct mt76_reg_pair vals[] = { + /* Copied from MediaTek reference source */ + { MT_PBF_SYS_CTRL, 0x00080c00 }, + { MT_PBF_CFG, 0x1efebcff }, + { MT_FCE_PSE_CTRL, 0x00000001 }, + { MT_MAC_SYS_CTRL, 0x0000000c }, + { MT_MAX_LEN_CFG, 0x003e3f00 }, + { MT_AMPDU_MAX_LEN_20M1S, 0xaaa99887 }, + { MT_AMPDU_MAX_LEN_20M2S, 0x000000aa }, + { MT_XIFS_TIME_CFG, 0x33a40d0a }, + { MT_BKOFF_SLOT_CFG, 0x00000209 }, + { MT_TBTT_SYNC_CFG, 0x00422010 }, + { MT_PWR_PIN_CFG, 0x00000000 }, + { 0x1238, 0x001700c8 }, + { MT_TX_SW_CFG0, 0x00101001 }, + { MT_TX_SW_CFG1, 0x00010000 }, + { MT_TX_SW_CFG2, 0x00000000 }, + { MT_TXOP_CTRL_CFG, 0x0400583f }, + { MT_TX_RTS_CFG, 0x00100020 }, + { MT_TX_TIMEOUT_CFG, 0x000a2290 }, + { MT_TX_RETRY_CFG, 0x47f01f0f }, + { MT_EXP_ACK_TIME, 0x002c00dc }, + { MT_TX_PROT_CFG6, 0xe3f42004 }, + { MT_TX_PROT_CFG7, 0xe3f42084 }, + { MT_TX_PROT_CFG8, 0xe3f42104 }, + { MT_PIFS_TX_CFG, 0x00060fff }, + { MT_RX_FILTR_CFG, 0x00015f97 }, + { MT_LEGACY_BASIC_RATE, 0x0000017f }, + { MT_HT_BASIC_RATE, 0x00004003 }, + { MT_PN_PAD_MODE, 0x00000003 }, + { MT_TXOP_HLDR_ET, 0x00000002 }, + { 0xa44, 0x00000000 }, + { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, + { MT_TSO_CTRL, 0x00000000 }, + { MT_AUX_CLK_CFG, 0x00000000 }, + { MT_DACCLK_EN_DLY_CFG, 0x00000000 }, + { MT_TX_ALC_CFG_4, 0x00000000 }, + { MT_TX_ALC_VGA3, 0x00000000 }, + { MT_TX_PWR_CFG_0, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_1, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_2, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_3, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_4, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_7, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_8, 0x0000003a }, + { MT_TX_PWR_CFG_9, 0x0000003a }, + { MT_EFUSE_CTRL, 0x0000d000 }, + { MT_PAUSE_ENABLE_CONTROL1, 0x0000000a }, + { MT_FCE_WLAN_FLOW_CONTROL1, 0x60401c18 }, + { MT_WPDMA_DELAY_INT_CFG, 0x94ff0000 }, + { MT_TX_SW_CFG3, 0x00000004 }, + { MT_HT_FBK_TO_LEGACY, 0x00001818 }, + { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, + { MT_PROT_AUTO_TX_CFG, 0x00830083 }, + { MT_HT_CTRL_CFG, 0x000001ff }, + }; + struct mt76_reg_pair prot_vals[] = { + { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK }, + { MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG_OFDM }, + { MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 }, + { MT_MM40_PROT_CFG, DEFAULT_PROT_CFG_40 }, + { MT_GF20_PROT_CFG, DEFAULT_PROT_CFG_20 }, + { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, + }; + + mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals)); + mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals)); +} +EXPORT_SYMBOL_GPL(mt76_write_mac_initvals); + +void mt76x2_init_device(struct mt76x2_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + + hw->queues = 4; + hw->max_rates = 1; + hw->max_report_rates = 7; + hw->max_rate_tries = 1; + hw->extra_tx_headroom = 2; + + hw->sta_data_size = sizeof(struct mt76x02_sta); + hw->vif_data_size = sizeof(struct mt76x02_vif); + + ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); + + dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + + dev->mt76.chainmask = 0x202; + dev->mt76.global_wcid.idx = 255; + dev->mt76.global_wcid.hw_key_idx = -1; + dev->slottime = 9; + + /* init antenna configuration */ + dev->mt76.antenna_mask = 3; +} +EXPORT_SYMBOL_GPL(mt76x2_init_device); + +void mt76x2_init_txpower(struct mt76x2_dev *dev, + struct ieee80211_supported_band *sband) +{ + struct ieee80211_channel *chan; + struct mt76x2_tx_power_info txp; + struct mt76_rate_power t = {}; + int target_power; + int i; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + + mt76x2_get_power_info(dev, &txp, chan); + + target_power = max_t(int, (txp.chain[0].target_power + + txp.chain[0].delta), + (txp.chain[1].target_power + + txp.chain[1].delta)); + + mt76x2_get_rate_power(dev, &t, chan); + + chan->max_power = mt76x02_get_max_rate_power(&t) + + target_power; + chan->max_power /= 2; + + /* convert to combined output power on 2x2 devices */ + chan->max_power += 3; + } +} +EXPORT_SYMBOL_GPL(mt76x2_init_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c new file mode 100644 index 000000000000..568bac76097c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "../mt76x02_util.h" + +void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) +{ + bool stopped = false; + u32 rts_cfg; + int i; + + mt76_wr(dev, MT_MAC_SYS_CTRL, 0); + + rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); + + /* Wait for MAC to become idle */ + for (i = 0; i < 300; i++) { + if ((mt76_rr(dev, MT_MAC_STATUS) & + (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || + mt76_rr(dev, MT_BBP(IBI, 12))) { + udelay(1); + continue; + } + + stopped = true; + break; + } + + if (force && !stopped) { + mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); + + mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); + } + + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); +} +EXPORT_SYMBOL_GPL(mt76x2_mac_stop); + +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, int len) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + struct ieee80211_key_conf *key = info->control.hw_key; + u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); + u8 nss; + s8 txpwr_adj, max_txpwr_adj; + u8 ccmp_pn[8]; + + memset(txwi, 0, sizeof(*txwi)); + + if (wcid) + txwi->wcid = wcid->idx; + else + txwi->wcid = 0xff; + + txwi->pktid = 1; + + if (wcid && wcid->sw_iv && key) { + u64 pn = atomic64_inc_return(&key->tx_pn); + ccmp_pn[0] = pn; + ccmp_pn[1] = pn >> 8; + ccmp_pn[2] = 0; + ccmp_pn[3] = 0x20 | (key->keyidx << 6); + ccmp_pn[4] = pn >> 16; + ccmp_pn[5] = pn >> 24; + ccmp_pn[6] = pn >> 32; + ccmp_pn[7] = pn >> 40; + txwi->iv = *((__le32 *)&ccmp_pn[0]); + txwi->eiv = *((__le32 *)&ccmp_pn[1]); + } + + spin_lock_bh(&dev->mt76.lock); + if (wcid && (rate->idx < 0 || !rate->count)) { + txwi->rate = wcid->tx_rate; + max_txpwr_adj = wcid->max_txpwr_adj; + nss = wcid->tx_rate_nss; + } else { + txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); + max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(&dev->mt76, rate); + } + spin_unlock_bh(&dev->mt76.lock); + + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, + max_txpwr_adj); + txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); + + if (mt76xx_rev(dev) >= MT76XX_REV_E4) + txwi->txstream = 0x13; + else if (mt76xx_rev(dev) >= MT76XX_REV_E3 && + !(txwi->rate & cpu_to_le16(rate_ht_mask))) + txwi->txstream = 0x93; + + mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); +} +EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); + +int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) +{ + struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; + + rssi += cal->rssi_offset[chain]; + rssi -= cal->lna_gain; + + return rssi; +} + +static struct mt76x02_sta * +mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) +{ + struct mt76_wcid *wcid; + + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + return NULL; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (!wcid) + return NULL; + + return container_of(wcid, struct mt76x02_sta, wcid); +} + +static struct mt76_wcid * +mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x02_sta *sta, + bool unicast) +{ + if (!sta) + return NULL; + + if (unicast) + return &sta->wcid; + else + return &sta->vif->group_wcid; +} + +int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, + void *rxi) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct mt76x02_rxwi *rxwi = rxi; + struct mt76x02_sta *sta; + u32 rxinfo = le32_to_cpu(rxwi->rxinfo); + u32 ctl = le32_to_cpu(rxwi->ctl); + u16 rate = le16_to_cpu(rxwi->rate); + u16 tid_sn = le16_to_cpu(rxwi->tid_sn); + bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); + int pad_len = 0; + u8 pn_len; + u8 wcid; + int len; + + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return -EINVAL; + + if (rxinfo & MT_RXINFO_L2PAD) + pad_len += 2; + + if (rxinfo & MT_RXINFO_DECRYPT) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_MMIC_STRIPPED; + status->flag |= RX_FLAG_MIC_STRIPPED; + status->flag |= RX_FLAG_IV_STRIPPED; + } + + wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); + sta = mt76x2_rx_get_sta(dev, wcid); + status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast); + + len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); + if (pn_len) { + int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; + u8 *data = skb->data + offset; + + status->iv[0] = data[7]; + status->iv[1] = data[6]; + status->iv[2] = data[5]; + status->iv[3] = data[4]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + + /* + * Driver CCMP validation can't deal with fragments. + * Let mac80211 take care of it. + */ + if (rxinfo & MT_RXINFO_FRAG) { + status->flag &= ~RX_FLAG_IV_STRIPPED; + } else { + pad_len += pn_len << 2; + len -= pn_len << 2; + } + } + + mt76x02_remove_hdr_pad(skb, pad_len); + + if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) + status->aggr = true; + + if (WARN_ON_ONCE(len > skb->len)) + return -EINVAL; + + pskb_trim(skb, len); + status->chains = BIT(0) | BIT(1); + status->chain_signal[0] = mt76x2_mac_get_rssi(dev, rxwi->rssi[0], 0); + status->chain_signal[1] = mt76x2_mac_get_rssi(dev, rxwi->rssi[1], 1); + status->signal = max(status->chain_signal[0], status->chain_signal[1]); + status->freq = dev->mt76.chandef.chan->center_freq; + status->band = dev->mt76.chandef.chan->band; + + status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); + status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); + + if (sta) { + ewma_signal_add(&sta->rssi, status->signal); + sta->inactive_count = 0; + } + + return mt76x02_mac_process_rate(status, rate); +} +EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h new file mode 100644 index 000000000000..b2176f9a661a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 __MT76x2_MAC_H +#define __MT76x2_MAC_H + +#include "../mt76.h" +#include "../mt76x02_mac.h" + +struct mt76x2_dev; +struct mt76x2_sta; +struct mt76x02_vif; + +struct mt76x2_tx_info { + unsigned long jiffies; + u8 tries; + + u8 wcid; + u8 pktid; + u8 retry; +}; + +static inline struct mt76x2_tx_info * +mt76x2_skb_tx_info(struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + return (void *) info->status.status_driver_data; +} + +int mt76x2_mac_start(struct mt76x2_dev *dev); +void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force); +void mt76x2_mac_resume(struct mt76x2_dev *dev); +void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); + +int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, + void *rxi); +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, int len); + +int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, + struct sk_buff *skb); +void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val); + +void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq); +void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev); + +void mt76x2_mac_work(struct work_struct *work); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c new file mode 100644 index 000000000000..86b09534326e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 +#include +#include + +#include "mt76x2.h" +#include "mcu.h" +#include "eeprom.h" +#include "../mt76x02_dma.h" + +int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, + u8 bw_index, bool scan) +{ + struct sk_buff *skb; + struct { + u8 idx; + u8 scan; + u8 bw; + u8 _pad0; + + __le16 chainmask; + u8 ext_chan; + u8 _pad1; + + } __packed __aligned(4) msg = { + .idx = channel, + .scan = scan, + .bw = bw, + .chainmask = cpu_to_le16(dev->mt76.chainmask), + }; + + /* first set the channel without the extension channel info */ + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); + + usleep_range(5000, 10000); + + msg.ext_chan = 0xe0 + bw_index; + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); + +int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, + u8 channel) +{ + struct mt76_dev *mdev = &dev->mt76; + struct sk_buff *skb; + struct { + u8 cr_mode; + u8 temp; + u8 ch; + u8 _pad0; + + __le32 cfg; + } __packed __aligned(4) msg = { + .cr_mode = type, + .temp = temp_level, + .ch = channel, + }; + u32 val; + + val = BIT(31); + val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; + val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00; + msg.cfg = cpu_to_le32(val); + + /* first set the channel without the extension channel info */ + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); + +int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, + bool force) +{ + struct sk_buff *skb; + struct { + __le32 channel; + __le32 gain_val; + } __packed __aligned(4) msg = { + .channel = cpu_to_le32(channel), + .gain_val = cpu_to_le32(gain), + }; + + if (force) + msg.channel |= cpu_to_le32(BIT(31)); + + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); + +int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, + struct mt76x2_tssi_comp *tssi_data) +{ + struct sk_buff *skb; + struct { + __le32 id; + struct mt76x2_tssi_comp data; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(MCU_CAL_TSSI_COMP), + .data = *tssi_data, + }; + + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h new file mode 100644 index 000000000000..98a73e285a45 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 __MT76x2_MCU_H +#define __MT76x2_MCU_H + +#include "../mt76x02_mcu.h" + +/* Register definitions */ +#define MT_MCU_CPU_CTL 0x0704 +#define MT_MCU_CLOCK_CTL 0x0708 +#define MT_MCU_PCIE_REMAP_BASE1 0x0740 +#define MT_MCU_PCIE_REMAP_BASE2 0x0744 +#define MT_MCU_PCIE_REMAP_BASE3 0x0748 + +#define MT_LED_CTRL 0x0770 +#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) +#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) +#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) +#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) + +#define MT_LED_TX_BLINK_0 0x0774 +#define MT_LED_TX_BLINK_1 0x0778 + +#define MT_LED_S0_BASE 0x077C +#define MT_LED_S0(_n) (MT_LED_S0_BASE + 8 * (_n)) +#define MT_LED_S1_BASE 0x0780 +#define MT_LED_S1(_n) (MT_LED_S1_BASE + 8 * (_n)) +#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) +#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ + MT_LED_STATUS_OFF_MASK) +#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) +#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ + MT_LED_STATUS_ON_MASK) +#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 8) +#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ + MT_LED_STATUS_DURATION_MASK) + +#define MT_MCU_ROM_PATCH_OFFSET 0x80000 +#define MT_MCU_ROM_PATCH_ADDR 0x90000 + +#define MT_MCU_ILM_OFFSET 0x80000 + +#define MT_MCU_DLM_OFFSET 0x100000 +#define MT_MCU_DLM_ADDR 0x90000 +#define MT_MCU_DLM_ADDR_E3 0x90800 + +enum mcu_calibration { + MCU_CAL_R = 1, + MCU_CAL_TEMP_SENSOR, + MCU_CAL_RXDCOC, + MCU_CAL_RC, + MCU_CAL_SX_LOGEN, + MCU_CAL_LC, + MCU_CAL_TX_LOFT, + MCU_CAL_TXIQ, + MCU_CAL_TSSI, + MCU_CAL_TSSI_COMP, + MCU_CAL_DPD, + MCU_CAL_RXIQC_FI, + MCU_CAL_RXIQC_FD, + MCU_CAL_PWRON, + MCU_CAL_TX_SHAPING, +}; + +enum mt76x2_mcu_cr_mode { + MT_RF_CR, + MT_BBP_CR, + MT_RF_BBP_CR, + MT_HL_TEMP_CR_UPDATE, +}; + +struct mt76x2_tssi_comp { + u8 pa_mode; + u8 cal_mode; + u16 pad; + + u8 slope0; + u8 slope1; + u8 offset0; + u8 offset1; +} __packed __aligned(4); + +int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); +int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, + bool force); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h new file mode 100644 index 000000000000..ecbb9e4ab888 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 __MT76x2_H +#define __MT76x2_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT7662_FIRMWARE "mt7662.bin" +#define MT7662_ROM_PATCH "mt7662_rom_patch.bin" +#define MT7662_EEPROM_SIZE 512 + +#define MT7662U_FIRMWARE "mediatek/mt7662u.bin" +#define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin" + +#define MT_MAX_CHAINS 2 + +#define MT_CALIBRATE_INTERVAL HZ + +#include "../mt76.h" +#include "../mt76x02_regs.h" +#include "mac.h" +#include "dfs.h" + +struct mt76x2_rx_freq_cal { + s8 high_gain[MT_MAX_CHAINS]; + s8 rssi_offset[MT_MAX_CHAINS]; + s8 lna_gain; + u32 mcu_gain; +}; + +struct mt76x2_calibration { + struct mt76x2_rx_freq_cal rx; + + u8 agc_gain_init[MT_MAX_CHAINS]; + u8 agc_gain_cur[MT_MAX_CHAINS]; + + u16 false_cca; + s8 avg_rssi_all; + s8 agc_gain_adjust; + s8 low_gain; + + u8 temp; + + bool init_cal_done; + bool tssi_cal_done; + bool tssi_comp_pending; + bool dpd_cal_done; + bool channel_cal_done; +}; + +struct mt76x2_dev { + struct mt76_dev mt76; /* must be first */ + + struct mac_address macaddr_list[8]; + + struct mutex mutex; + + u8 txdone_seq; + DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); + + struct sk_buff *rx_head; + + struct tasklet_struct tx_tasklet; + struct tasklet_struct pre_tbtt_tasklet; + struct delayed_work cal_work; + struct delayed_work mac_work; + + u32 aggr_stats[32]; + + struct sk_buff *beacons[8]; + u8 beacon_mask; + u8 beacon_data_mask; + + u8 tbtt_count; + u16 beacon_int; + + struct mt76x2_calibration cal; + + s8 target_power; + s8 target_power_delta[2]; + bool enable_tpc; + + u8 coverage_class; + u8 slottime; + + struct mt76x2_dfs_pattern_detector dfs_pd; +}; + +static inline bool is_mt7612(struct mt76x2_dev *dev) +{ + return mt76_chip(&dev->mt76) == 0x7612; +} + +static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + + return ((chan->flags & IEEE80211_CHAN_RADAR) && + chan->dfs_state != NL80211_DFS_AVAILABLE); +} + +extern const struct ieee80211_ops mt76x2_ops; + +struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); +int mt76x2_register_device(struct mt76x2_dev *dev); +void mt76x2_init_debugfs(struct mt76x2_dev *dev); +void mt76x2_init_device(struct mt76x2_dev *dev); + +irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance); +void mt76x2_phy_power_on(struct mt76x2_dev *dev); +int mt76x2_init_hardware(struct mt76x2_dev *dev); +void mt76x2_stop_hardware(struct mt76x2_dev *dev); +int mt76x2_eeprom_init(struct mt76x2_dev *dev); +int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel); +void mt76x2_set_tx_ackto(struct mt76x2_dev *dev); + +void mt76x2_phy_set_antenna(struct mt76x2_dev *dev); +int mt76x2_phy_start(struct mt76x2_dev *dev); +int mt76x2_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef); +int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain); +void mt76x2_phy_calibrate(struct work_struct *work); +void mt76x2_phy_set_txpower(struct mt76x2_dev *dev); + +int mt76x2_mcu_init(struct mt76x2_dev *dev); +int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, + u8 bw_index, bool scan); +int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, + u8 channel); + +void mt76x2_tx_tasklet(unsigned long data); +void mt76x2_dma_cleanup(struct mt76x2_dev *dev); + +void mt76x2_cleanup(struct mt76x2_dev *dev); + +void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); +void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); +void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val); + +void mt76x2_pre_tbtt_tasklet(unsigned long arg); + +void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); + +void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); + +void mt76x2_update_channel(struct mt76_dev *mdev); + +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate); +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); +void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); + + +void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); +void mt76x2_init_txpower(struct mt76x2_dev *dev, + struct ieee80211_supported_band *sband); +void mt76_write_mac_initvals(struct mt76x2_dev *dev); + +int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt76x2_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); +void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); + +void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait); +void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, + enum nl80211_band band); +void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, + enum nl80211_band band, u8 bw); +void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl); +void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper); +int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev); +void mt76x2_apply_gain_adj(struct mt76x2_dev *dev); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h new file mode 100644 index 000000000000..969e8e15fc58 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 __MT76x2U_H +#define __MT76x2U_H + +#include + +#include "mt76x2.h" +#include "mcu.h" +#include "../mt76x02_dma.h" + +#define MT7612U_EEPROM_SIZE 512 + +#define MT_USB_AGGR_SIZE_LIMIT 21 /* 1024B unit */ +#define MT_USB_AGGR_TIMEOUT 0x80 /* 33ns unit */ + +extern const struct ieee80211_ops mt76x2u_ops; + +struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev); +int mt76x2u_register_device(struct mt76x2_dev *dev); +int mt76x2u_init_hardware(struct mt76x2_dev *dev); +void mt76x2u_cleanup(struct mt76x2_dev *dev); +void mt76x2u_stop_hw(struct mt76x2_dev *dev); + +int mt76x2u_mac_reset(struct mt76x2_dev *dev); +void mt76x2u_mac_resume(struct mt76x2_dev *dev); +int mt76x2u_mac_start(struct mt76x2_dev *dev); +int mt76x2u_mac_stop(struct mt76x2_dev *dev); + +int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef); +void mt76x2u_phy_calibrate(struct work_struct *work); +void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev); + +void mt76x2u_mcu_complete_urb(struct urb *urb); +int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, + bool ext, int rssi, u32 false_cca); +int mt76x2u_mcu_init(struct mt76x2_dev *dev); +int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); + +int mt76x2u_alloc_queues(struct mt76x2_dev *dev); +void mt76x2u_queues_deinit(struct mt76x2_dev *dev); +void mt76x2u_stop_queues(struct mt76x2_dev *dev); +int mt76x2u_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); +int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, + u32 flags); + +#endif /* __MT76x2U_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c new file mode 100644 index 000000000000..49556becb72d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include +#include + +#include "mt76x2.h" +#include "trace.h" + +static const struct pci_device_id mt76pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7662) }, + { PCI_DEVICE(0x14c3, 0x7612) }, + { PCI_DEVICE(0x14c3, 0x7602) }, + { }, +}; + +static int +mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mt76x2_dev *dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dev = mt76x2_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + 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_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + + ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x2_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt76x2_register_device(dev); + if (ret) + goto error; + + /* Fix up ASPM configuration */ + + /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ + mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); + + /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ + mt76_rmw_field(dev, 0x15a0c, 0xf << 28, 0xf); + + /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ + mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); + + return 0; + +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void +mt76pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + + mt76_unregister_device(mdev); + mt76x2_cleanup(dev); + ieee80211_free_hw(mdev->hw); +} + +MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +MODULE_FIRMWARE(MT7662_FIRMWARE); +MODULE_FIRMWARE(MT7662_ROM_PATCH); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct pci_driver mt76pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76pci_device_table, + .probe = mt76pci_probe, + .remove = mt76pci_remove, +}; + +module_pci_driver(mt76pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c new file mode 100644 index 000000000000..b343742b36ee --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include "mt76x2.h" +#include "trace.h" +#include "../mt76x02_util.h" + +void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + mt76x02_irq_enable(mdev, MT_INT_RX_DONE(q)); +} + +irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) +{ + struct mt76x2_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) + return IRQ_NONE; + + trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask); + + intr &= dev->mt76.mmio.irqmask; + + if (intr & MT_INT_TX_DONE_ALL) { + mt76x02_irq_disable(&dev->mt76, MT_INT_TX_DONE_ALL); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_RX_DONE(0)) { + mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(0)); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE(1)) { + mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(1)); + napi_schedule(&dev->mt76.napi[1]); + } + + if (intr & MT_INT_PRE_TBTT) + tasklet_schedule(&dev->pre_tbtt_tasklet); + + /* send buffered multicast frames now */ + if (intr & MT_INT_TBTT) + mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); + + if (intr & MT_INT_TX_STAT) { + mt76x2_mac_poll_tx_status(dev, true); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_GPTIMER) { + mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); + tasklet_schedule(&dev->dfs_pd.dfs_tasklet); + } + + return IRQ_HANDLED; +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c new file mode 100644 index 000000000000..18926a6478ab --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c @@ -0,0 +1,878 @@ +/* + * Copyright (C) 2016 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "../mt76x02_util.h" + +#define RADAR_SPEC(m, len, el, eh, wl, wh, \ + w_tolerance, tl, th, t_tolerance, \ + bl, bh, event_exp, power_jmp) \ +{ \ + .mode = m, \ + .avg_len = len, \ + .e_low = el, \ + .e_high = eh, \ + .w_low = wl, \ + .w_high = wh, \ + .w_margin = w_tolerance, \ + .t_low = tl, \ + .t_high = th, \ + .t_margin = t_tolerance, \ + .b_low = bl, \ + .b_high = bh, \ + .event_expiration = event_exp, \ + .pwr_jmp = power_jmp \ +} + +static const struct mt76x2_radar_specs etsi_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc) +}; + +static const struct mt76x2_radar_specs fcc_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0xfe808, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0xfe808, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0, + 0x7fffffff, 0xfe808, 0x16cc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289) +}; + +static const struct mt76x2_radar_specs jp_w56_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0x14c080, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0x14c080, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0, + 0x7fffffff, 0x14c080, 0x16cc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289) +}; + +static const struct mt76x2_radar_specs jp_w53_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 } +}; + +static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, + u8 enable) +{ + u32 data; + + data = (1 << 1) | enable; + mt76_wr(dev, MT_BBP(DFS, 36), data); +} + +static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev, + struct mt76x2_dfs_sequence *seq) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + list_add(&seq->head, &dfs_pd->seq_pool); + + dfs_pd->seq_stats.seq_pool_len++; + dfs_pd->seq_stats.seq_len--; +} + +static +struct mt76x2_dfs_sequence *mt76x2_dfs_seq_pool_get(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq; + + if (list_empty(&dfs_pd->seq_pool)) { + seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); + } else { + seq = list_first_entry(&dfs_pd->seq_pool, + struct mt76x2_dfs_sequence, + head); + list_del(&seq->head); + dfs_pd->seq_stats.seq_pool_len--; + } + if (seq) + dfs_pd->seq_stats.seq_len++; + + return seq; +} + +static int mt76x2_dfs_get_multiple(int val, int frac, int margin) +{ + int remainder, factor; + + if (!frac) + return 0; + + if (abs(val - frac) <= margin) + return 1; + + factor = val / frac; + remainder = val % frac; + + if (remainder > margin) { + if ((frac - remainder) <= margin) + factor++; + else + factor = 0; + } + return factor; +} + +static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq, *tmp_seq; + int i; + + /* reset hw detector */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + + /* reset sw detector */ + for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { + dfs_pd->event_rb[i].h_rb = 0; + dfs_pd->event_rb[i].t_rb = 0; + } + + list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { + list_del_init(&seq->head); + mt76x2_dfs_seq_pool_put(dev, seq); + } +} + +static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) +{ + bool ret = false; + u32 current_ts, delta_ts; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); + delta_ts = current_ts - dfs_pd->chirp_pulse_ts; + dfs_pd->chirp_pulse_ts = current_ts; + + /* 12 sec */ + if (delta_ts <= (12 * (1 << 20))) { + if (++dfs_pd->chirp_pulse_cnt > 8) + ret = true; + } else { + dfs_pd->chirp_pulse_cnt = 1; + } + + return ret; +} + +static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev, + struct mt76x2_dfs_hw_pulse *pulse) +{ + u32 data; + + /* select channel */ + data = (MT_DFS_CH_EN << 16) | pulse->engine; + mt76_wr(dev, MT_BBP(DFS, 0), data); + + /* reported period */ + pulse->period = mt76_rr(dev, MT_BBP(DFS, 19)); + + /* reported width */ + pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20)); + pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23)); + + /* reported burst number */ + pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); +} + +static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, + struct mt76x2_dfs_hw_pulse *pulse) +{ + bool ret = false; + + if (!pulse->period || !pulse->w1) + return false; + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + if (pulse->engine > 3) + break; + + if (pulse->engine == 3) { + ret = mt76x2_dfs_check_chirp(dev); + break; + } + + /* check short pulse*/ + if (pulse->w1 < 120) + ret = (pulse->period >= 2900 && + (pulse->period <= 4700 || + pulse->period >= 6400) && + (pulse->period <= 6800 || + pulse->period >= 10200) && + pulse->period <= 61600); + else if (pulse->w1 < 130) /* 120 - 130 */ + ret = (pulse->period >= 2900 && + pulse->period <= 61600); + else + ret = (pulse->period >= 3500 && + pulse->period <= 10100); + break; + case NL80211_DFS_ETSI: + if (pulse->engine >= 3) + break; + + ret = (pulse->period >= 4900 && + (pulse->period <= 10200 || + pulse->period >= 12400) && + pulse->period <= 100100); + break; + case NL80211_DFS_JP: + if (dev->mt76.chandef.chan->center_freq >= 5250 && + dev->mt76.chandef.chan->center_freq <= 5350) { + /* JPW53 */ + if (pulse->w1 <= 130) + ret = (pulse->period >= 28360 && + (pulse->period <= 28700 || + pulse->period >= 76900) && + pulse->period <= 76940); + break; + } + + if (pulse->engine > 3) + break; + + if (pulse->engine == 3) { + ret = mt76x2_dfs_check_chirp(dev); + break; + } + + /* check short pulse*/ + if (pulse->w1 < 120) + ret = (pulse->period >= 2900 && + (pulse->period <= 4700 || + pulse->period >= 6400) && + (pulse->period <= 6800 || + pulse->period >= 27560) && + (pulse->period <= 27960 || + pulse->period >= 28360) && + (pulse->period <= 28700 || + pulse->period >= 79900) && + pulse->period <= 80100); + else if (pulse->w1 < 130) /* 120 - 130 */ + ret = (pulse->period >= 2900 && + (pulse->period <= 10100 || + pulse->period >= 27560) && + (pulse->period <= 27960 || + pulse->period >= 28360) && + (pulse->period <= 28700 || + pulse->period >= 79900) && + pulse->period <= 80100); + else + ret = (pulse->period >= 3900 && + pulse->period <= 10100); + break; + case NL80211_DFS_UNSET: + default: + return false; + } + + return ret; +} + +static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + u32 data; + + /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2) + * 2nd: DFS_R37[21:0]: pulse time + * 3rd: DFS_R37[11:0]: pulse width + * 3rd: DFS_R37[25:16]: phase + * 4th: DFS_R37[12:0]: current pwr + * 4th: DFS_R37[21:16]: pwr stable counter + * + * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected + */ + data = mt76_rr(dev, MT_BBP(DFS, 37)); + if (!MT_DFS_CHECK_EVENT(data)) + return false; + + event->engine = MT_DFS_EVENT_ENGINE(data); + data = mt76_rr(dev, MT_BBP(DFS, 37)); + event->ts = MT_DFS_EVENT_TIMESTAMP(data); + data = mt76_rr(dev, MT_BBP(DFS, 37)); + event->width = MT_DFS_EVENT_WIDTH(data); + + return true; +} + +static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + if (event->engine == 2) { + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; + u16 last_event_idx; + u32 delta_ts; + + last_event_idx = mt76_decr(event_buff->t_rb, + MT_DFS_EVENT_BUFLEN); + delta_ts = event->ts - event_buff->data[last_event_idx].ts; + if (delta_ts < MT_DFS_EVENT_TIME_MARGIN && + event_buff->data[last_event_idx].width >= 200) + return false; + } + return true; +} + +static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff; + + /* add radar event to ring buffer */ + event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] + : &dfs_pd->event_rb[0]; + event_buff->data[event_buff->t_rb] = *event; + event_buff->data[event_buff->t_rb].fetch_ts = jiffies; + + event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); + if (event_buff->t_rb == event_buff->h_rb) + event_buff->h_rb = mt76_incr(event_buff->h_rb, + MT_DFS_EVENT_BUFLEN); +} + +static int mt76x2_dfs_create_sequence(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event, + u16 cur_len) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sw_detector_params *sw_params; + u32 width_delta, with_sum, factor, cur_pri; + struct mt76x2_dfs_sequence seq, *seq_p; + struct mt76x2_dfs_event_rb *event_rb; + struct mt76x2_dfs_event *cur_event; + int i, j, end, pri; + + event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] + : &dfs_pd->event_rb[0]; + + i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN); + end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN); + + while (i != end) { + cur_event = &event_rb->data[i]; + with_sum = event->width + cur_event->width; + + sw_params = &dfs_pd->sw_dpd_params; + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + case NL80211_DFS_JP: + if (with_sum < 600) + width_delta = 8; + else + width_delta = with_sum >> 3; + break; + case NL80211_DFS_ETSI: + if (event->engine == 2) + width_delta = with_sum >> 6; + else if (with_sum < 620) + width_delta = 24; + else + width_delta = 8; + break; + case NL80211_DFS_UNSET: + default: + return -EINVAL; + } + + pri = event->ts - cur_event->ts; + if (abs(event->width - cur_event->width) > width_delta || + pri < sw_params->min_pri) + goto next; + + if (pri > sw_params->max_pri) + break; + + seq.pri = event->ts - cur_event->ts; + seq.first_ts = cur_event->ts; + seq.last_ts = event->ts; + seq.engine = event->engine; + seq.count = 2; + + j = mt76_decr(i, MT_DFS_EVENT_BUFLEN); + while (j != end) { + cur_event = &event_rb->data[j]; + cur_pri = event->ts - cur_event->ts; + factor = mt76x2_dfs_get_multiple(cur_pri, seq.pri, + sw_params->pri_margin); + if (factor > 0) { + seq.first_ts = cur_event->ts; + seq.count++; + } + + j = mt76_decr(j, MT_DFS_EVENT_BUFLEN); + } + if (seq.count <= cur_len) + goto next; + + seq_p = mt76x2_dfs_seq_pool_get(dev); + if (!seq_p) + return -ENOMEM; + + *seq_p = seq; + INIT_LIST_HEAD(&seq_p->head); + list_add(&seq_p->head, &dfs_pd->sequences); +next: + i = mt76_decr(i, MT_DFS_EVENT_BUFLEN); + } + return 0; +} + +static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sw_detector_params *sw_params; + struct mt76x2_dfs_sequence *seq, *tmp_seq; + u16 max_seq_len = 0; + u32 factor, pri; + + sw_params = &dfs_pd->sw_dpd_params; + list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { + if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) { + list_del_init(&seq->head); + mt76x2_dfs_seq_pool_put(dev, seq); + continue; + } + + if (event->engine != seq->engine) + continue; + + pri = event->ts - seq->last_ts; + factor = mt76x2_dfs_get_multiple(pri, seq->pri, + sw_params->pri_margin); + if (factor > 0) { + seq->last_ts = event->ts; + seq->count++; + max_seq_len = max_t(u16, max_seq_len, seq->count); + } + } + return max_seq_len; +} + +static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq; + + if (list_empty(&dfs_pd->sequences)) + return false; + + list_for_each_entry(seq, &dfs_pd->sequences, head) { + if (seq->count > MT_DFS_SEQUENCE_TH) { + dfs_pd->stats[seq->engine].sw_pattern++; + return true; + } + } + return false; +} + +static void mt76x2_dfs_add_events(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event event; + int i, seq_len; + + /* disable debug mode */ + mt76x2_dfs_set_capture_mode_ctrl(dev, false); + for (i = 0; i < MT_DFS_EVENT_LOOP; i++) { + if (!mt76x2_dfs_fetch_event(dev, &event)) + break; + + if (dfs_pd->last_event_ts > event.ts) + mt76x2_dfs_detector_reset(dev); + dfs_pd->last_event_ts = event.ts; + + if (!mt76x2_dfs_check_event(dev, &event)) + continue; + + seq_len = mt76x2_dfs_add_event_to_sequence(dev, &event); + mt76x2_dfs_create_sequence(dev, &event, seq_len); + + mt76x2_dfs_queue_event(dev, &event); + } + mt76x2_dfs_set_capture_mode_ctrl(dev, true); +} + +static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff; + struct mt76x2_dfs_event *event; + int i; + + for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { + event_buff = &dfs_pd->event_rb[i]; + + while (event_buff->h_rb != event_buff->t_rb) { + event = &event_buff->data[event_buff->h_rb]; + + /* sorted list */ + if (time_is_after_jiffies(event->fetch_ts + + MT_DFS_EVENT_WINDOW)) + break; + event_buff->h_rb = mt76_incr(event_buff->h_rb, + MT_DFS_EVENT_BUFLEN); + } + } +} + +static void mt76x2_dfs_tasklet(unsigned long arg) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *)arg; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + u32 engine_mask; + int i; + + if (test_bit(MT76_SCANNING, &dev->mt76.state)) + goto out; + + if (time_is_before_jiffies(dfs_pd->last_sw_check + + MT_DFS_SW_TIMEOUT)) { + bool radar_detected; + + dfs_pd->last_sw_check = jiffies; + + mt76x2_dfs_add_events(dev); + radar_detected = mt76x2_dfs_check_detection(dev); + if (radar_detected) { + /* sw detector rx radar pattern */ + ieee80211_radar_detected(dev->mt76.hw); + mt76x2_dfs_detector_reset(dev); + + return; + } + mt76x2_dfs_check_event_window(dev); + } + + engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); + if (!(engine_mask & 0xf)) + goto out; + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + struct mt76x2_dfs_hw_pulse pulse; + + if (!(engine_mask & (1 << i))) + continue; + + pulse.engine = i; + mt76x2_dfs_get_hw_pulse(dev, &pulse); + + if (!mt76x2_dfs_check_hw_pulse(dev, &pulse)) { + dfs_pd->stats[i].hw_pulse_discarded++; + continue; + } + + /* hw detector rx radar pattern */ + dfs_pd->stats[i].hw_pattern++; + ieee80211_radar_detected(dev->mt76.hw); + mt76x2_dfs_detector_reset(dev); + + return; + } + + /* reset hw detector */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + +out: + mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); +} + +static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; + break; + case NL80211_DFS_ETSI: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2; + break; + case NL80211_DFS_JP: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; + break; + case NL80211_DFS_UNSET: + default: + break; + } +} + +static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) +{ + u32 data; + u8 i, shift; + const struct mt76x2_radar_specs *radar_specs; + + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_40: + shift = MT_DFS_NUM_ENGINES; + break; + case NL80211_CHAN_WIDTH_80: + shift = 2 * MT_DFS_NUM_ENGINES; + break; + default: + shift = 0; + break; + } + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + radar_specs = &fcc_radar_specs[shift]; + break; + case NL80211_DFS_ETSI: + radar_specs = &etsi_radar_specs[shift]; + break; + case NL80211_DFS_JP: + if (dev->mt76.chandef.chan->center_freq >= 5250 && + dev->mt76.chandef.chan->center_freq <= 5350) + radar_specs = &jp_w53_radar_specs[shift]; + else + radar_specs = &jp_w56_radar_specs[shift]; + break; + case NL80211_DFS_UNSET: + default: + return; + } + + data = (MT_DFS_VGA_MASK << 16) | + (MT_DFS_PWR_GAIN_OFFSET << 12) | + (MT_DFS_PWR_DOWN_TIME << 8) | + (MT_DFS_SYM_ROUND << 4) | + (MT_DFS_DELTA_DELAY & 0xf); + mt76_wr(dev, MT_BBP(DFS, 2), data); + + data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK; + mt76_wr(dev, MT_BBP(DFS, 3), data); + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + /* configure engine */ + mt76_wr(dev, MT_BBP(DFS, 0), i); + + /* detection mode + avg_len */ + data = ((radar_specs[i].avg_len & 0x1ff) << 16) | + (radar_specs[i].mode & 0xf); + mt76_wr(dev, MT_BBP(DFS, 4), data); + + /* dfs energy */ + data = ((radar_specs[i].e_high & 0x0fff) << 16) | + (radar_specs[i].e_low & 0x0fff); + mt76_wr(dev, MT_BBP(DFS, 5), data); + + /* dfs period */ + mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low); + mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high); + + /* dfs burst */ + mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low); + mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high); + + /* dfs width */ + data = ((radar_specs[i].w_high & 0x0fff) << 16) | + (radar_specs[i].w_low & 0x0fff); + mt76_wr(dev, MT_BBP(DFS, 14), data); + + /* dfs margins */ + data = (radar_specs[i].w_margin << 16) | + radar_specs[i].t_margin; + mt76_wr(dev, MT_BBP(DFS, 15), data); + + /* dfs event expiration */ + mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration); + + /* dfs pwr adj */ + mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp); + } + + /* reset status */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + mt76_wr(dev, MT_BBP(DFS, 36), 0x3); + + /* enable detection*/ + mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); + mt76_wr(dev, 0x212c, 0x0c350001); +} + +void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev) +{ + u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31; + + agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8)); + agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4)); + + val_r8 = (agc_r8 & 0x00007e00) >> 9; + val_r4 = agc_r4 & ~0x1f000000; + val_r4 += (((val_r8 + 1) >> 1) << 24); + mt76_wr(dev, MT_BBP(AGC, 4), val_r4); + + dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4); + dfs_r31 += val_r8; + dfs_r31 -= (agc_r8 & 0x00000038) >> 3; + dfs_r31 = (dfs_r31 << 16) | 0x00000307; + mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31); + + mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071); +} + +void mt76x2_dfs_init_params(struct mt76x2_dev *dev) +{ + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + + if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + dev->dfs_pd.region != NL80211_DFS_UNSET) { + mt76x2_dfs_init_sw_detector(dev); + mt76x2_dfs_set_bbp_params(dev); + /* enable debug mode */ + mt76x2_dfs_set_capture_mode_ctrl(dev, true); + + mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); + mt76_rmw_field(dev, MT_INT_TIMER_EN, + MT_INT_TIMER_EN_GP_TIMER_EN, 1); + } else { + /* disable hw detector */ + mt76_wr(dev, MT_BBP(DFS, 0), 0); + /* clear detector status */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + mt76_wr(dev, 0x212c, 0); + + mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); + mt76_rmw_field(dev, MT_INT_TIMER_EN, + MT_INT_TIMER_EN_GP_TIMER_EN, 0); + } +} + +void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + INIT_LIST_HEAD(&dfs_pd->sequences); + INIT_LIST_HEAD(&dfs_pd->seq_pool); + dfs_pd->region = NL80211_DFS_UNSET; + dfs_pd->last_sw_check = jiffies; + tasklet_init(&dfs_pd->dfs_tasklet, mt76x2_dfs_tasklet, + (unsigned long)dev); +} + +void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, + enum nl80211_dfs_regions region) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + if (dfs_pd->region != region) { + tasklet_disable(&dfs_pd->dfs_tasklet); + dfs_pd->region = region; + mt76x2_dfs_init_params(dev); + tasklet_enable(&dfs_pd->dfs_tasklet); + } +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c new file mode 100644 index 000000000000..fdd5103e8c93 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 "mt76x2.h" +#include "../mt76x02_dma.h" +#include "../mt76x02_util.h" + +void mt76x2_tx_tasklet(unsigned long data) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) data; + int i; + + mt76x2_mac_process_tx_status_fifo(dev); + + for (i = MT_TXQ_MCU; i >= 0; i--) + mt76_queue_tx_cleanup(dev, i, false); + + mt76x2_mac_poll_tx_status(dev, false); + mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); +} + +void mt76x2_dma_cleanup(struct mt76x2_dev *dev) +{ + tasklet_kill(&dev->tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c new file mode 100644 index 000000000000..7036f4cbc836 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include "mt76x2.h" +#include "eeprom.h" +#include "mcu.h" +#include "../mt76x02_util.h" +#include "../mt76x02_dma.h" + +static void +mt76x2_mac_pbf_init(struct mt76x2_dev *dev) +{ + u32 val; + + val = MT_PBF_SYS_CTRL_MCU_RESET | + MT_PBF_SYS_CTRL_DMA_RESET | + MT_PBF_SYS_CTRL_MAC_RESET | + MT_PBF_SYS_CTRL_PBF_RESET | + MT_PBF_SYS_CTRL_ASY_RESET; + + mt76_set(dev, MT_PBF_SYS_CTRL, val); + mt76_clear(dev, MT_PBF_SYS_CTRL, val); + + mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); + mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); +} + +static void +mt76x2_fixup_xtal(struct mt76x2_dev *dev) +{ + u16 eep_val; + s8 offset = 0; + + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); + + offset = eep_val & 0x7f; + if ((eep_val & 0xff) == 0xff) + offset = 0; + else if (eep_val & 0x80) + offset = 0 - offset; + + eep_val >>= 8; + if (eep_val == 0x00 || eep_val == 0xff) { + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); + eep_val &= 0xff; + + if (eep_val == 0x00 || eep_val == 0xff) + eep_val = 0x14; + } + + eep_val &= 0x7f; + mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); + mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); + + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { + case 0: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); + break; + case 1: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); + break; + default: + break; + } +} + +static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) +{ + static const u8 null_addr[ETH_ALEN] = {}; + const u8 *macaddr = dev->mt76.macaddr; + u32 val; + int i, k; + + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + val = mt76_rr(dev, MT_WPDMA_GLO_CFG); + + val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY | + MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); + val |= FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); + + mt76_wr(dev, MT_WPDMA_GLO_CFG, val); + + mt76x2_mac_pbf_init(dev); + mt76_write_mac_initvals(dev); + mt76x2_fixup_xtal(dev); + + mt76_clear(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP); + + if (is_mt7612(dev)) + mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); + + mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); + mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); + + mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); + mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); + usleep_range(5000, 10000); + mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); + + mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); + mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); + + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(macaddr)); + mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(macaddr + 4)); + + mt76_wr(dev, MT_MAC_BSSID_DW0, get_unaligned_le32(macaddr)); + mt76_wr(dev, MT_MAC_BSSID_DW1, get_unaligned_le16(macaddr + 4) | + FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ + MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); + + /* Fire a pre-TBTT interrupt 8 ms before TBTT */ + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, + 8 << 4); + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, + MT_DFS_GP_INTERVAL); + mt76_wr(dev, MT_INT_TIMER_EN, 0); + + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); + if (!hard) + return 0; + + for (i = 0; i < 256 / 32; i++) + mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); + + for (i = 0; i < 256; i++) + mt76x02_mac_wcid_setup(&dev->mt76, i, 0, NULL); + + for (i = 0; i < MT_MAX_VIFS; i++) + mt76x02_mac_wcid_setup(&dev->mt76, MT_VIF_WCID(i), i, NULL); + + for (i = 0; i < 16; i++) + for (k = 0; k < 4; k++) + mt76x02_mac_shared_key_setup(&dev->mt76, i, k, NULL); + + for (i = 0; i < 8; i++) { + mt76x2_mac_set_bssid(dev, i, null_addr); + mt76x2_mac_set_beacon(dev, i, NULL); + } + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + + mt76x02_set_beacon_offsets(&dev->mt76); + + mt76x2_set_tx_ackto(dev); + + return 0; +} + +int mt76x2_mac_start(struct mt76x2_dev *dev) +{ + int i; + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + mt76x02_mac_start(&dev->mt76); + + return 0; +} + +void mt76x2_mac_resume(struct mt76x2_dev *dev) +{ + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); +} + +static void +mt76x2_power_on_rf_patch(struct mt76x2_dev *dev) +{ + mt76_set(dev, 0x10130, BIT(0) | BIT(16)); + udelay(1); + + mt76_clear(dev, 0x1001c, 0xff); + mt76_set(dev, 0x1001c, 0x30); + + mt76_wr(dev, 0x10014, 0x484f); + udelay(1); + + mt76_set(dev, 0x10130, BIT(17)); + udelay(125); + + mt76_clear(dev, 0x10130, BIT(16)); + udelay(50); + + mt76_set(dev, 0x1014c, BIT(19) | BIT(20)); +} + +static void +mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit) +{ + int shift = unit ? 8 : 0; + + /* Enable RF BG */ + mt76_set(dev, 0x10130, BIT(0) << shift); + udelay(10); + + /* Enable RFDIG LDO/AFE/ABB/ADDA */ + mt76_set(dev, 0x10130, (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift); + udelay(10); + + /* Switch RFDIG power to internal LDO */ + mt76_clear(dev, 0x10130, BIT(2) << shift); + udelay(10); + + mt76x2_power_on_rf_patch(dev); + + mt76_set(dev, 0x530, 0xf); +} + +static void +mt76x2_power_on(struct mt76x2_dev *dev) +{ + u32 val; + + /* Turn on WL MTCMOS */ + mt76_set(dev, MT_WLAN_MTC_CTRL, MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); + + val = MT_WLAN_MTC_CTRL_STATE_UP | + MT_WLAN_MTC_CTRL_PWR_ACK | + MT_WLAN_MTC_CTRL_PWR_ACK_S; + + mt76_poll(dev, MT_WLAN_MTC_CTRL, val, val, 1000); + + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0x7f << 16); + udelay(10); + + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xf << 24); + udelay(10); + + mt76_set(dev, MT_WLAN_MTC_CTRL, 0xf << 24); + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xfff); + + /* Turn on AD/DA power down */ + mt76_clear(dev, 0x11204, BIT(3)); + + /* WLAN function enable */ + mt76_set(dev, 0x10080, BIT(0)); + + /* Release BBP software reset */ + mt76_clear(dev, 0x10064, BIT(18)); + + mt76x2_power_on_rf(dev, 0); + mt76x2_power_on_rf(dev, 1); +} + +void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) +{ + u8 ackto, sifs, slottime = dev->slottime; + + /* As defined by IEEE 802.11-2007 17.3.8.6 */ + slottime += 3 * dev->coverage_class; + mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, + MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); + + sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, + MT_XIFS_TIME_CFG_OFDM_SIFS); + + ackto = slottime + sifs; + mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, + MT_TX_TIMEOUT_CFG_ACKTO, ackto); +} + +int mt76x2_init_hardware(struct mt76x2_dev *dev) +{ + int ret; + + tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, + (unsigned long) dev); + + mt76x02_dma_disable(&dev->mt76); + mt76x2_reset_wlan(dev, true); + mt76x2_power_on(dev); + + ret = mt76x2_eeprom_init(dev); + if (ret) + return ret; + + ret = mt76x2_mac_reset(dev, true); + if (ret) + return ret; + + dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + + ret = mt76x02_dma_init(&dev->mt76); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + ret = mt76x2_mac_start(dev); + if (ret) + return ret; + + ret = mt76x2_mcu_init(dev); + if (ret) + return ret; + + mt76x2_mac_stop(dev, false); + + return 0; +} + +void mt76x2_stop_hardware(struct mt76x2_dev *dev) +{ + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + mt76x02_mcu_set_radio_state(&dev->mt76, false, true); + mt76x2_mac_stop(dev, false); +} + +void mt76x2_cleanup(struct mt76x2_dev *dev) +{ + tasklet_disable(&dev->dfs_pd.dfs_tasklet); + tasklet_disable(&dev->pre_tbtt_tasklet); + mt76x2_stop_hardware(dev); + mt76x2_dma_cleanup(dev); + mt76x02_mcu_cleanup(&dev->mt76); +} + +struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .update_survey = mt76x2_update_channel, + .tx_prepare_skb = mt76x2_tx_prepare_skb, + .tx_complete_skb = mt76x2_tx_complete_skb, + .rx_skb = mt76x2_queue_rx_skb, + .rx_poll_complete = mt76x2_rx_poll_complete, + .sta_ps = mt76x2_sta_ps, + .get_max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj, + }; + struct mt76x2_dev *dev; + struct mt76_dev *mdev; + + mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops); + if (!mdev) + return NULL; + + dev = container_of(mdev, struct mt76x2_dev, mt76); + mdev->dev = pdev; + mdev->drv = &drv_ops; + + return dev; +} + +static void mt76x2_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt76x2_dev *dev = hw->priv; + + mt76x2_dfs_set_domain(dev, request->dfs_region); +} + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = 8, + .types = BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), + } +}; + +static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on, + u8 delay_off) +{ + struct mt76x2_dev *dev = container_of(mt76, struct mt76x2_dev, + mt76); + u32 val; + + val = MT_LED_STATUS_DURATION(0xff) | + MT_LED_STATUS_OFF(delay_off) | + MT_LED_STATUS_ON(delay_on); + + mt76_wr(dev, MT_LED_S0(mt76->led_pin), val); + mt76_wr(dev, MT_LED_S1(mt76->led_pin), val); + + val = MT_LED_CTRL_REPLAY(mt76->led_pin) | + MT_LED_CTRL_KICK(mt76->led_pin); + if (mt76->led_al) + val |= MT_LED_CTRL_POLARITY(mt76->led_pin); + mt76_wr(dev, MT_LED_CTRL, val); +} + +static int mt76x2_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt76x2_led_set_config(mt76, delta_on, delta_off); + return 0; +} + +static void mt76x2_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + + if (!brightness) + mt76x2_led_set_config(mt76, 0, 0xff); + else + mt76x2_led_set_config(mt76, 0xff, 0); +} + +int mt76x2_register_device(struct mt76x2_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + void *status_fifo; + int fifo_size; + int i, ret; + + fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); + status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); + if (!status_fifo) + return -ENOMEM; + + tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long)dev); + kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); + INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); + INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); + + mt76x2_init_device(dev); + + ret = mt76x2_init_hardware(dev); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { + u8 *addr = dev->macaddr_list[i].addr; + + memcpy(addr, dev->mt76.macaddr, ETH_ALEN); + + if (!i) + continue; + + addr[0] |= BIT(1); + addr[0] ^= ((i - 1) << 2); + } + wiphy->addresses = dev->macaddr_list; + wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + + wiphy->reg_notifier = mt76x2_regd_notifier; + + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + mt76x2_dfs_init_detector(dev); + + /* init led callbacks */ + dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; + + ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); + if (ret) + goto fail; + + mt76x2_init_debugfs(dev); + mt76x2_init_txpower(dev, &dev->mt76.sband_2g.sband); + mt76x2_init_txpower(dev, &dev->mt76.sband_5g.sband); + + return 0; + +fail: + mt76x2_stop_hardware(dev); + return ret; +} + + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c new file mode 100644 index 000000000000..c1be3fe8cc90 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include "mt76x2.h" +#include "mcu.h" +#include "eeprom.h" +#include "trace.h" +#include "../mt76x02_util.h" + +void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) +{ + idx &= 7; + mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); + mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR, + get_unaligned_le16(addr + 4)); +} + +void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) +{ + struct mt76x02_tx_status stat = {}; + unsigned long flags; + u8 update = 1; + bool ret; + + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return; + + trace_mac_txstat_poll(dev); + + while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { + spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); + ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); + spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); + + if (!ret) + break; + + trace_mac_txstat_fetch(dev, &stat); + + if (!irq) { + mt76x02_send_tx_status(&dev->mt76, &stat, &update); + continue; + } + + kfifo_put(&dev->txstatus_fifo, stat); + } +} + +static void +mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, + void *txwi_ptr) +{ + struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); + struct mt76x02_txwi *txwi = txwi_ptr; + + mt76x2_mac_poll_tx_status(dev, false); + + txi->tries = 0; + txi->jiffies = jiffies; + txi->wcid = txwi->wcid; + txi->pktid = txwi->pktid; + trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); + mt76x02_tx_complete(&dev->mt76, skb); +} + +void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) +{ + struct mt76x02_tx_status stat; + u8 update = 1; + + while (kfifo_get(&dev->txstatus_fifo, &stat)) + mt76x02_send_tx_status(&dev->mt76, &stat, &update); +} + +void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + + if (e->txwi) + mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); + else + dev_kfree_skb_any(e->skb); +} + +static int +mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) +{ + int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; + struct mt76x02_txwi txwi; + + if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) + return -ENOSPC; + + mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); + + mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); + offset += sizeof(txwi); + + mt76_wr_copy(dev, offset, skb->data, skb->len); + return 0; +} + +static int +__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) +{ + int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; + int beacon_addr = mt76x02_beacon_offsets[bcn_idx]; + int ret = 0; + int i; + + /* Prevent corrupt transmissions during update */ + mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); + + if (skb) { + ret = mt76_write_beacon(dev, beacon_addr, skb); + if (!ret) + dev->beacon_data_mask |= BIT(bcn_idx); + } else { + dev->beacon_data_mask &= ~BIT(bcn_idx); + for (i = 0; i < beacon_len; i += 4) + mt76_wr(dev, beacon_addr + i, 0); + } + + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); + + return ret; +} + +int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, + struct sk_buff *skb) +{ + bool force_update = false; + int bcn_idx = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { + if (vif_idx == i) { + force_update = !!dev->beacons[i] ^ !!skb; + + if (dev->beacons[i]) + dev_kfree_skb(dev->beacons[i]); + + dev->beacons[i] = skb; + __mt76x2_mac_set_beacon(dev, bcn_idx, skb); + } else if (force_update && dev->beacons[i]) { + __mt76x2_mac_set_beacon(dev, bcn_idx, dev->beacons[i]); + } + + bcn_idx += !!dev->beacons[i]; + } + + for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { + if (!(dev->beacon_data_mask & BIT(i))) + break; + + __mt76x2_mac_set_beacon(dev, i, NULL); + } + + mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, + bcn_idx - 1); + return 0; +} + +void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) +{ + u8 old_mask = dev->beacon_mask; + bool en; + u32 reg; + + if (val) { + dev->beacon_mask |= BIT(vif_idx); + } else { + dev->beacon_mask &= ~BIT(vif_idx); + mt76x2_mac_set_beacon(dev, vif_idx, NULL); + } + + if (!!old_mask == !!dev->beacon_mask) + return; + + en = dev->beacon_mask; + + mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); + reg = MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_TIMER_EN; + mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); + + if (en) + mt76x02_irq_enable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); + else + mt76x02_irq_disable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); +} + +void mt76x2_update_channel(struct mt76_dev *mdev) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76_channel_state *state; + u32 active, busy; + + state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + + busy = mt76_rr(dev, MT_CH_BUSY); + active = busy + mt76_rr(dev, MT_CH_IDLE); + + spin_lock_bh(&dev->mt76.cc_lock); + state->cc_busy += busy; + state->cc_active += active; + spin_unlock_bh(&dev->mt76.cc_lock); +} + +void mt76x2_mac_work(struct work_struct *work) +{ + struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev, + mac_work.work); + int i, idx; + + mt76x2_update_channel(&dev->mt76); + for (i = 0, idx = 0; i < 16; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->aggr_stats[idx++] += val & 0xffff; + dev->aggr_stats[idx++] += val >> 16; + } + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + MT_CALIBRATE_INTERVAL); +} + +void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val) +{ + u32 data = 0; + + if (val != ~0) + data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) | + MT_PROT_CFG_RTS_THRESH; + + mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val); + + mt76_rmw(dev, MT_CCK_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_OFDM_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_MM20_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_MM40_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_GF20_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_GF40_PROT_CFG, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_TX_PROT_CFG6, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_TX_PROT_CFG7, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); + mt76_rmw(dev, MT_TX_PROT_CFG8, + MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c new file mode 100644 index 000000000000..521c9265bfe0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 "mt76x2.h" +#include "../mt76x02_util.h" + +static int +mt76x2_start(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mt76.mutex); + + ret = mt76x2_mac_start(dev); + if (ret) + goto out; + + ret = mt76x2_phy_start(dev); + if (ret) + goto out; + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + MT_CALIBRATE_INTERVAL); + + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + +out: + mutex_unlock(&dev->mt76.mutex); + return ret; +} + +static void +mt76x2_stop(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x2_stop_hardware(dev); + mutex_unlock(&dev->mt76.mutex); +} + +static int +mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) +{ + int ret; + + cancel_delayed_work_sync(&dev->cal_work); + + set_bit(MT76_RESET, &dev->mt76.state); + + mt76_set_channel(&dev->mt76); + + tasklet_disable(&dev->pre_tbtt_tasklet); + tasklet_disable(&dev->dfs_pd.dfs_tasklet); + + mt76x2_mac_stop(dev, true); + ret = mt76x2_phy_set_channel(dev, chandef); + + /* channel cycle counters read-and-clear */ + mt76_rr(dev, MT_CH_IDLE); + mt76_rr(dev, MT_CH_BUSY); + + mt76x2_dfs_init_params(dev); + + mt76x2_mac_resume(dev); + tasklet_enable(&dev->dfs_pd.dfs_tasklet); + tasklet_enable(&dev->pre_tbtt_tasklet); + + clear_bit(MT76_RESET, &dev->mt76.state); + + mt76_txq_schedule_all(&dev->mt76); + + return ret; +} + +static int +mt76x2_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + int ret = 0; + + mutex_lock(&dev->mt76.mutex); + + 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); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + dev->mt76.txpower_conf = hw->conf.power_level * 2; + + /* convert to per-chain power for 2x2 devices */ + dev->mt76.txpower_conf -= 6; + + if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { + mt76x2_phy_set_txpower(dev); + mt76x2_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); + } + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt76x2_set_channel(dev, &hw->conf.chandef); + ieee80211_wake_queues(hw); + } + + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static void +mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + + mutex_lock(&dev->mt76.mutex); + + if (changed & BSS_CHANGED_BSSID) + mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); + + if (changed & BSS_CHANGED_BEACON_INT) { + mt76_rmw_field(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_INTVAL, + info->beacon_int << 4); + dev->beacon_int = info->beacon_int; + dev->tbtt_count = 0; + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + tasklet_disable(&dev->pre_tbtt_tasklet); + mt76x2_mac_set_beacon_enable(dev, mvif->idx, + info->enable_beacon); + tasklet_enable(&dev->pre_tbtt_tasklet); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + dev->slottime = slottime; + mt76x2_set_tx_ackto(dev); + } + + mutex_unlock(&dev->mt76.mutex); +} + +void +mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) +{ + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + int idx = msta->wcid.idx; + + mt76_stop_tx_queues(&dev->mt76, sta, true); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, ps); +} + +static void +mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac) +{ + struct mt76x2_dev *dev = hw->priv; + + tasklet_disable(&dev->pre_tbtt_tasklet); + set_bit(MT76_SCANNING, &dev->mt76.state); +} + +static void +mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + clear_bit(MT76_SCANNING, &dev->mt76.state); + tasklet_enable(&dev->pre_tbtt_tasklet); +} + +static void +mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ +} + +static int +mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) +{ + struct mt76x2_dev *dev = hw->priv; + + *dbm = dev->mt76.txpower_cur / 2; + + /* convert from per-chain power to combined output on 2x2 devices */ + *dbm += 3; + + return 0; +} + +static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + dev->coverage_class = coverage_class; + mt76x2_set_tx_ackto(dev); + mutex_unlock(&dev->mt76.mutex); +} + +static int +mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + return 0; +} + +static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, + u32 rx_ant) +{ + struct mt76x2_dev *dev = hw->priv; + + if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) + return -EINVAL; + + mutex_lock(&dev->mt76.mutex); + + dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101; + dev->mt76.antenna_mask = tx_ant; + + mt76_set_stream_caps(&dev->mt76, true); + mt76x2_phy_set_antenna(dev); + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, + u32 *rx_ant) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + *tx_ant = dev->mt76.antenna_mask; + *rx_ant = dev->mt76.antenna_mask; + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +{ + struct mt76x2_dev *dev = hw->priv; + + if (val != ~0 && val > 0xffff) + return -EINVAL; + + mutex_lock(&dev->mutex); + mt76x2_mac_set_tx_protection(dev, val); + mutex_unlock(&dev->mutex); + + return 0; +} + +const struct ieee80211_ops mt76x2_ops = { + .tx = mt76x2_tx, + .start = mt76x2_start, + .stop = mt76x2_stop, + .add_interface = mt76x02_add_interface, + .remove_interface = mt76x02_remove_interface, + .config = mt76x2_config, + .configure_filter = mt76x02_configure_filter, + .bss_info_changed = mt76x2_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 = mt76x2_sw_scan, + .sw_scan_complete = mt76x2_sw_scan_complete, + .flush = mt76x2_flush, + .ampdu_action = mt76x02_ampdu_action, + .get_txpower = mt76x2_get_txpower, + .wake_tx_queue = mt76_wake_tx_queue, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, + .release_buffered_frames = mt76_release_buffered_frames, + .set_coverage_class = mt76x2_set_coverage_class, + .get_survey = mt76_get_survey, + .set_tim = mt76x2_set_tim, + .set_antenna = mt76x2_set_antenna, + .get_antenna = mt76x2_get_antenna, + .set_rts_threshold = mt76x2_set_rts_threshold, +}; + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c new file mode 100644 index 000000000000..38fa84bddf7b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include +#include + +#include "mt76x2.h" +#include "mcu.h" +#include "eeprom.h" +#include "../mt76x02_dma.h" + +static int +mt76pci_load_rom_patch(struct mt76x2_dev *dev) +{ + const struct firmware *fw = NULL; + struct mt76x02_patch_header *hdr; + bool rom_protect = !is_mt7612(dev); + int len, ret = 0; + __le32 *cur; + u32 patch_mask, patch_reg; + + if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { + dev_err(dev->mt76.dev, + "Could not get hardware semaphore for ROM PATCH\n"); + return -ETIMEDOUT; + } + + if (mt76xx_rev(dev) >= MT76XX_REV_E3) { + patch_mask = BIT(0); + patch_reg = MT_MCU_CLOCK_CTL; + } else { + patch_mask = BIT(1); + patch_reg = MT_MCU_COM_REG0; + } + + if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { + dev_info(dev->mt76.dev, "ROM patch already applied\n"); + goto out; + } + + ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { + ret = -EIO; + dev_err(dev->mt76.dev, "Failed to load firmware\n"); + goto out; + } + + hdr = (struct mt76x02_patch_header *)fw->data; + dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); + + cur = (__le32 *) (fw->data + sizeof(*hdr)); + len = fw->size - sizeof(*hdr); + mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + + /* Trigger ROM */ + mt76_wr(dev, MT_MCU_INT_LEVEL, 4); + + if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) { + dev_err(dev->mt76.dev, "Failed to load ROM patch\n"); + ret = -ETIMEDOUT; + } + +out: + /* release semaphore */ + if (rom_protect) + mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); + release_firmware(fw); + return ret; +} + +static int +mt76pci_load_firmware(struct mt76x2_dev *dev) +{ + const struct firmware *fw; + const struct mt76x02_fw_header *hdr; + int len, ret; + __le32 *cur; + u32 offset, val; + + ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto error; + + 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) + goto error; + + 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->build_ver); + dev_info(dev->mt76.dev, "Build: %x\n", val); + dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); + + cur = (__le32 *) (fw->data + sizeof(*hdr)); + len = le32_to_cpu(hdr->ilm_len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len); + + cur += len / sizeof(*cur); + len = le32_to_cpu(hdr->dlm_len); + + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + offset = MT_MCU_DLM_ADDR_E3; + else + offset = MT_MCU_DLM_ADDR; + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); + mt76_wr_copy(dev, offset, cur, len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) + mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); + + /* trigger firmware */ + mt76_wr(dev, MT_MCU_INT_LEVEL, 2); + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + release_firmware(fw); + return -ETIMEDOUT; + } + + dev_info(dev->mt76.dev, "Firmware running!\n"); + mt76x02_set_ethtool_fwver(&dev->mt76, hdr); + + release_firmware(fw); + + return ret; + +error: + dev_err(dev->mt76.dev, "Invalid firmware\n"); + release_firmware(fw); + return -ENOENT; +} + +int mt76x2_mcu_init(struct mt76x2_dev *dev) +{ + static const struct mt76_mcu_ops mt76x2_mcu_ops = { + .mcu_msg_alloc = mt76x02_mcu_msg_alloc, + .mcu_send_msg = mt76x02_mcu_msg_send, + }; + int ret; + + dev->mt76.mcu_ops = &mt76x2_mcu_ops; + + ret = mt76pci_load_rom_patch(dev); + if (ret) + return ret; + + ret = mt76pci_load_firmware(dev); + if (ret) + return ret; + + mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, true); + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c new file mode 100644 index 000000000000..392601310e39 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 +#include "mt76x2.h" +#include "mcu.h" +#include "eeprom.h" + +static bool +mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + u32 flag = 0; + + if (!mt76x02_tssi_enabled(&dev->mt76)) + return false; + + if (mt76x2_channel_silent(dev)) + return false; + + if (chan->band == NL80211_BAND_5GHZ) + flag |= BIT(0); + + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + flag |= BIT(8); + + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); + dev->cal.tssi_cal_done = true; + return true; +} + +static void +mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + bool is_5ghz = chan->band == NL80211_BAND_5GHZ; + + if (dev->cal.channel_cal_done) + return; + + if (mt76x2_channel_silent(dev)) + return; + + if (!dev->cal.tssi_cal_done) + mt76x2_phy_tssi_init_cal(dev); + + if (!mac_stopped) + mt76x2_mac_stop(dev, false); + + if (is_5ghz) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, true); + + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_SHAPING, 0, true); + + if (!mac_stopped) + mt76x2_mac_resume(dev); + + mt76x2_apply_gain_adj(dev); + + dev->cal.channel_cal_done = true; +} + +void mt76x2_phy_set_antenna(struct mt76x2_dev *dev) +{ + u32 val; + + val = mt76_rr(dev, MT_BBP(AGC, 0)); + val &= ~(BIT(4) | BIT(1)); + switch (dev->mt76.antenna_mask) { + case 1: + /* disable mac DAC control */ + mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_clear(dev, MT_BBP(TXBE, 5), 3); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0x3); + mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 2); + /* disable DAC 1 */ + mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 4); + + val &= ~(BIT(3) | BIT(0)); + break; + case 2: + /* disable mac DAC control */ + mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_rmw_field(dev, MT_BBP(TXBE, 5), 3, 1); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xc); + mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 1); + /* disable DAC 0 */ + mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 1); + + val &= ~BIT(3); + val |= BIT(0); + break; + case 3: + default: + /* enable mac DAC control */ + mt76_set(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_set(dev, MT_BBP(TXBE, 5), 3); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xf); + mt76_clear(dev, MT_BBP(CORE, 32), GENMASK(21, 20)); + mt76_clear(dev, MT_BBP(CORE, 33), GENMASK(12, 9)); + + val &= ~BIT(0); + val |= BIT(3); + break; + } + mt76_wr(dev, MT_BBP(AGC, 0), val); +} + +static void +mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest) +{ + dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); + dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); +} + +static int +mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -62; + case NL80211_CHAN_WIDTH_40: + return -65; + default: + return -68; + } +} + +static int +mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -76; + case NL80211_CHAN_WIDTH_40: + return -79; + default: + return -82; + } +} + +static void +mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) +{ + u32 val; + u8 gain_val[2]; + + gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; + gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; + + if (dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40) + val = 0x1e42 << 16; + else + val = 0x1836 << 16; + + val |= 0xf8; + + mt76_wr(dev, MT_BBP(AGC, 8), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); + mt76_wr(dev, MT_BBP(AGC, 9), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); + + if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) + mt76x2_dfs_adjust_agc(dev); +} + +static void +mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) +{ + u32 false_cca; + u8 limit = dev->cal.low_gain > 0 ? 16 : 4; + + false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); + dev->cal.false_cca = false_cca; + if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) + dev->cal.agc_gain_adjust += 2; + else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) || + (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) + dev->cal.agc_gain_adjust -= 2; + else + return; + + mt76x2_phy_set_gain_val(dev); +} + +static void +mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) +{ + u8 *gain = dev->cal.agc_gain_init; + u8 low_gain_delta, gain_delta; + bool gain_change; + int low_gain; + u32 val; + + dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); + + low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + + (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); + + gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2); + dev->cal.low_gain = low_gain; + + if (!gain_change) { + mt76x2_phy_adjust_vga_gain(dev); + return; + } + + if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) { + mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); + val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf; + if (low_gain == 2) + val |= 0x3; + else + val |= 0x5; + mt76_wr(dev, MT_BBP(AGC, 26), val); + } else { + mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); + } + + if (mt76x2_has_ext_lna(dev)) + low_gain_delta = 10; + else + low_gain_delta = 14; + + if (low_gain == 2) { + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); + mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); + mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); + gain_delta = low_gain_delta; + dev->cal.agc_gain_adjust = 0; + } else { + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); + if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) + mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014); + else + mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116); + mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C); + gain_delta = 0; + dev->cal.agc_gain_adjust = low_gain_delta; + } + + dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; + dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; + mt76x2_phy_set_gain_val(dev); + + /* clear false CCA counters */ + mt76_rr(dev, MT_RX_STAT_1); +} + +int mt76x2_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_channel *chan = chandef->chan; + bool scan = test_bit(MT76_SCANNING, &dev->mt76.state); + enum nl80211_band band = chan->band; + u8 channel; + + u32 ext_cca_chan[4] = { + [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(0)), + [1] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(1)), + [2] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(2)), + [3] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(3)), + }; + int ch_group_index; + u8 bw, bw_index; + int freq, freq1; + int ret; + + dev->cal.channel_cal_done = false; + freq = chandef->chan->center_freq; + freq1 = chandef->center_freq1; + channel = chan->hw_value; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + bw = 1; + if (freq1 > freq) { + bw_index = 1; + ch_group_index = 0; + } else { + bw_index = 3; + ch_group_index = 1; + } + channel += 2 - ch_group_index * 4; + break; + case NL80211_CHAN_WIDTH_80: + ch_group_index = (freq - freq1 + 30) / 20; + if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) + ch_group_index = 0; + bw = 2; + bw_index = ch_group_index; + channel += 6 - ch_group_index * 4; + break; + default: + bw = 0; + bw_index = 0; + ch_group_index = 0; + break; + } + + mt76x2_read_rx_gain(dev); + mt76x2_phy_set_txpower_regs(dev, band); + mt76x2_configure_tx_delay(dev, band, bw); + mt76x2_phy_set_txpower(dev); + + mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); + mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); + + mt76_rmw(dev, MT_EXT_CCA_CFG, + (MT_EXT_CCA_CFG_CCA0 | + MT_EXT_CCA_CFG_CCA1 | + MT_EXT_CCA_CFG_CCA2 | + MT_EXT_CCA_CFG_CCA3 | + MT_EXT_CCA_CFG_CCA_MASK), + ext_cca_chan[ch_group_index]); + + ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); + if (ret) + return ret; + + mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); + + mt76x2_phy_set_antenna(dev); + + /* Enable LDPC Rx */ + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); + + if (!dev->cal.init_cal_done) { + u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); + + if (val != 0xff) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); + } + + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, true); + + /* Rx LPF calibration */ + if (!dev->cal.init_cal_done) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, true); + + dev->cal.init_cal_done = true; + + mt76_wr(dev, MT_BBP(AGC, 61), 0xFF64A4E2); + mt76_wr(dev, MT_BBP(AGC, 7), 0x08081010); + mt76_wr(dev, MT_BBP(AGC, 11), 0x00000404); + mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); + mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x04101B3F); + + if (scan) + return 0; + + dev->cal.low_gain = -1; + mt76x2_phy_channel_calibrate(dev, true); + mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init); + memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, + sizeof(dev->cal.agc_gain_cur)); + + /* init default values for temp compensation */ + if (mt76x02_tssi_enabled(&dev->mt76)) { + mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + 0x38); + mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, + 0x38); + } + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); + + return 0; +} + +static void +mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) +{ + struct mt76x2_temp_comp t; + int temp, db_diff; + + if (mt76x2_get_temp_comp(dev, &t)) + return; + + temp = mt76_get_field(dev, MT_TEMP_SENSOR, MT_TEMP_SENSOR_VAL); + temp -= t.temp_25_ref; + temp = (temp * 1789) / 1000 + 25; + dev->cal.temp = temp; + + if (temp > 25) + db_diff = (temp - 25) / t.high_slope; + else + db_diff = (25 - temp) / t.low_slope; + + db_diff = min(db_diff, t.upper_bound); + db_diff = max(db_diff, t.lower_bound); + + mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + db_diff * 2); + mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, + db_diff * 2); +} + +void mt76x2_phy_calibrate(struct work_struct *work) +{ + struct mt76x2_dev *dev; + + dev = container_of(work, struct mt76x2_dev, cal_work.work); + mt76x2_phy_channel_calibrate(dev, false); + mt76x2_phy_tssi_compensate(dev, true); + mt76x2_phy_temp_compensate(dev); + mt76x2_phy_update_channel_gain(dev); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); +} + +int mt76x2_phy_start(struct mt76x2_dev *dev) +{ + int ret; + + ret = mt76x02_mcu_set_radio_state(&dev->mt76, true, true); + if (ret) + return ret; + + mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); + + return ret; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c new file mode 100644 index 000000000000..ea4ab8729ae4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c new file mode 100644 index 000000000000..69dc1f368f52 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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 "mt76x2.h" +#include "../mt76x02_util.h" +#include "../mt76x02_dma.h" + +struct beacon_bc_data { + struct mt76x2_dev *dev; + struct sk_buff_head q; + struct sk_buff *tail[8]; +}; + +int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int qsel = MT_QSEL_EDCA; + int ret; + + if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) + mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); + + mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); + + ret = mt76x02_insert_hdr_pad(skb); + if (ret < 0) + return ret; + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + qsel = MT_QSEL_MGMT; + + *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | + MT_TXD_INFO_80211; + + if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) + *tx_info |= MT_TXD_INFO_WIV; + + return 0; +} + +static void +mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct sk_buff *skb = NULL; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_beacon_get(mt76_hw(dev), vif); + if (!skb) + return; + + mt76x2_mac_set_beacon(dev, mvif->idx, skb); +} + +static void +mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct beacon_bc_data *data = priv; + struct mt76x2_dev *dev = data->dev; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct ieee80211_tx_info *info; + struct sk_buff *skb; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->control.vif = vif; + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + mt76_skb_set_moredata(skb, true); + __skb_queue_tail(&data->q, skb); + data->tail[mvif->idx] = skb; +} + +static void +mt76x2_resync_beacon_timer(struct mt76x2_dev *dev) +{ + u32 timer_val = dev->beacon_int << 4; + + dev->tbtt_count++; + + /* + * Beacon timer drifts by 1us every tick, the timer is configured + * in 1/16 TU (64us) units. + */ + if (dev->tbtt_count < 62) + return; + + if (dev->tbtt_count >= 64) { + dev->tbtt_count = 0; + return; + } + + /* + * The updated beacon interval takes effect after two TBTT, because + * at this point the original interval has already been loaded into + * the next TBTT_TIMER value + */ + if (dev->tbtt_count == 62) + timer_val -= 1; + + mt76_rmw_field(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_INTVAL, timer_val); +} + +void mt76x2_pre_tbtt_tasklet(unsigned long arg) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) arg; + struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD]; + struct beacon_bc_data data = {}; + struct sk_buff *skb; + int i, nframes; + + mt76x2_resync_beacon_timer(dev); + + data.dev = dev; + __skb_queue_head_init(&data.q); + + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76x2_update_beacon_iter, dev); + + do { + nframes = skb_queue_len(&data.q); + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76x2_add_buffered_bc, &data); + } while (nframes != skb_queue_len(&data.q)); + + if (!nframes) + return; + + for (i = 0; i < ARRAY_SIZE(data.tail); i++) { + if (!data.tail[i]) + continue; + + mt76_skb_set_moredata(data.tail[i], false); + } + + spin_lock_bh(&q->lock); + while ((skb = __skb_dequeue(&data.q)) != NULL) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + + mt76_dma_tx_queue_skb(&dev->mt76, q, skb, &mvif->group_wcid, + NULL); + } + spin_unlock_bh(&q->lock); +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c new file mode 100644 index 000000000000..b3ecb80340b5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "eeprom.h" +#include "mcu.h" +#include "../mt76x02_phy.h" + +static void +mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) +{ + s8 gain; + + gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); + gain -= offset / 2; + mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); +} + +static void +mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset) +{ + s8 gain; + + gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); + gain += offset; + mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); +} + +void mt76x2_apply_gain_adj(struct mt76x2_dev *dev) +{ + s8 *gain_adj = dev->cal.rx.high_gain; + + mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]); + mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]); + + mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]); + mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]); +} +EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj); + +void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, + enum nl80211_band band) +{ + u32 pa_mode[2]; + u32 pa_mode_adj; + + if (band == NL80211_BAND_2GHZ) { + pa_mode[0] = 0x010055ff; + pa_mode[1] = 0x00550055; + + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); + + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); + } else { + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200); + } + } else { + pa_mode[0] = 0x0000ffff; + pa_mode[1] = 0x00ff00ff; + + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); + } else { + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); + } + + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) + pa_mode_adj = 0x04000000; + else + pa_mode_adj = 0; + + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj); + } + + mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]); + mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]); + mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); + mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); + + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + u32 val; + + if (band == NL80211_BAND_2GHZ) + val = 0x3c3c023c; + else + val = 0x363c023c; + + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818); + } else { + if (band == NL80211_BAND_2GHZ) { + u32 val = 0x0f3c3c3c; + + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606); + } else { + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0); + } + } +} +EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); + +static int +mt76x2_get_min_rate_power(struct mt76_rate_power *r) +{ + int i; + s8 ret = 0; + + for (i = 0; i < sizeof(r->all); i++) { + if (!r->all[i]) + continue; + + if (ret) + ret = min(ret, r->all[i]); + else + ret = r->all[i]; + } + + return ret; +} + +void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) +{ + enum nl80211_chan_width width = dev->mt76.chandef.width; + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + struct mt76x2_tx_power_info txp; + int txp_0, txp_1, delta = 0; + struct mt76_rate_power t = {}; + int base_power, gain; + + mt76x2_get_power_info(dev, &txp, chan); + + if (width == NL80211_CHAN_WIDTH_40) + delta = txp.delta_bw40; + else if (width == NL80211_CHAN_WIDTH_80) + delta = txp.delta_bw80; + + mt76x2_get_rate_power(dev, &t, chan); + mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power); + mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf); + dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t); + + base_power = mt76x2_get_min_rate_power(&t); + delta += base_power - txp.chain[0].target_power; + txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta; + txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta; + + gain = min(txp_0, txp_1); + if (gain < 0) { + base_power -= gain; + txp_0 -= gain; + txp_1 -= gain; + } else if (gain > 0x2f) { + base_power -= gain - 0x2f; + txp_0 = 0x2f; + txp_1 = 0x2f; + } + + mt76x02_add_rate_power_offset(&t, -base_power); + dev->target_power = txp.chain[0].target_power; + dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; + dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; + dev->mt76.rate_power = t; + + mt76x02_phy_set_txpower(&dev->mt76, txp_0, txp_1); +} +EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); + +void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, + enum nl80211_band band, u8 bw) +{ + u32 cfg0, cfg1; + + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + cfg0 = bw ? 0x000b0c01 : 0x00101101; + cfg1 = 0x00011414; + } else { + cfg0 = bw ? 0x000b0b01 : 0x00101001; + cfg1 = 0x00021414; + } + mt76_wr(dev, MT_TX_SW_CFG0, cfg0); + mt76_wr(dev, MT_TX_SW_CFG1, cfg1); + + mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15); +} +EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); + +void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl) +{ + int core_val, agc_val; + + switch (width) { + case NL80211_CHAN_WIDTH_80: + core_val = 3; + agc_val = 7; + break; + case NL80211_CHAN_WIDTH_40: + core_val = 2; + agc_val = 3; + break; + default: + core_val = 0; + agc_val = 1; + break; + } + + mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); + mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); +} +EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw); + +void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) +{ + switch (band) { + case NL80211_BAND_2GHZ: + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + case NL80211_BAND_5GHZ: + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + } + + mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, + primary_upper); +} +EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); + +int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) +{ + struct mt76x02_sta *sta; + struct mt76_wcid *wcid; + int i, j, min_rssi = 0; + s8 cur_rssi; + + local_bh_disable(); + rcu_read_lock(); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { + unsigned long mask = dev->mt76.wcid_mask[i]; + + if (!mask) + continue; + + for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { + if (!(mask & 1)) + continue; + + wcid = rcu_dereference(dev->mt76.wcid[j]); + if (!wcid) + continue; + + sta = container_of(wcid, struct mt76x02_sta, wcid); + spin_lock(&dev->mt76.rx_lock); + if (sta->inactive_count++ < 5) + cur_rssi = ewma_signal_read(&sta->rssi); + else + cur_rssi = 0; + spin_unlock(&dev->mt76.rx_lock); + + if (cur_rssi < min_rssi) + min_rssi = cur_rssi; + } + } + + rcu_read_unlock(); + local_bh_enable(); + + if (!min_rssi) + return -75; + + return min_rssi; +} +EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi); + +void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + struct mt76x2_tx_power_info txp; + struct mt76x2_tssi_comp t = {}; + + if (!dev->cal.tssi_cal_done) + return; + + if (!dev->cal.tssi_comp_pending) { + /* TSSI trigger */ + t.cal_mode = BIT(0); + mt76x2_mcu_tssi_comp(dev, &t); + dev->cal.tssi_comp_pending = true; + } else { + if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) + return; + + dev->cal.tssi_comp_pending = false; + mt76x2_get_power_info(dev, &txp, chan); + + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + t.pa_mode = 1; + + t.cal_mode = BIT(1); + t.slope0 = txp.chain[0].tssi_slope; + t.offset0 = txp.chain[0].tssi_offset; + t.slope1 = txp.chain[1].tssi_slope; + t.offset1 = txp.chain[1].tssi_offset; + mt76x2_mcu_tssi_comp(dev, &t); + + if (t.pa_mode || dev->cal.dpd_cal_done) + return; + + usleep_range(10000, 20000); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, + chan->hw_value, wait); + dev->cal.dpd_cal_done = true; + } +} +EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h new file mode 100644 index 000000000000..9dceabace936 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * 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. + */ + +#if !defined(__MT76x2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MT76x2_TRACE_H + +#include +#include "mt76x2.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mt76x2 + +#define MAXNAME 32 +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) +#define DEV_PR_FMT "%s" +#define DEV_PR_ARG __entry->wiphy_name + +#define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) +#define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid +#define TXID_PR_FMT " [%d:%d]" +#define TXID_PR_ARG __entry->wcid, __entry->pktid + +DECLARE_EVENT_CLASS(dev_evt, + TP_PROTO(struct mt76x2_dev *dev), + TP_ARGS(dev), + TP_STRUCT__entry( + DEV_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + ), + TP_printk(DEV_PR_FMT, DEV_PR_ARG) +); + +DECLARE_EVENT_CLASS(dev_txid_evt, + TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid), + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + TXID_ASSIGN; + ), + TP_printk( + DEV_PR_FMT TXID_PR_FMT, + DEV_PR_ARG, TXID_PR_ARG + ) +); + +DEFINE_EVENT(dev_evt, mac_txstat_poll, + TP_PROTO(struct mt76x2_dev *dev), + TP_ARGS(dev) +); + +DEFINE_EVENT(dev_txid_evt, mac_txdone_add, + TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid) +); + +TRACE_EVENT(mac_txstat_fetch, + TP_PROTO(struct mt76x2_dev *dev, + struct mt76x02_tx_status *stat), + + TP_ARGS(dev, stat), + + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + __field(bool, success) + __field(bool, aggr) + __field(bool, ack_req) + __field(u16, rate) + __field(u8, retry) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->success = stat->success; + __entry->aggr = stat->aggr; + __entry->ack_req = stat->ack_req; + __entry->wcid = stat->wcid; + __entry->pktid = stat->pktid; + __entry->rate = stat->rate; + __entry->retry = stat->retry; + ), + + TP_printk( + DEV_PR_FMT TXID_PR_FMT + " success:%d aggr:%d ack_req:%d" + " rate:%04x retry:%d", + DEV_PR_ARG, TXID_PR_ARG, + __entry->success, __entry->aggr, __entry->ack_req, + __entry->rate, __entry->retry + ) +); + + +TRACE_EVENT(dev_irq, + TP_PROTO(struct mt76x2_dev *dev, u32 val, u32 mask), + + TP_ARGS(dev, val, mask), + + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, val) + __field(u32, mask) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->val = val; + __entry->mask = mask; + ), + + TP_printk( + DEV_PR_FMT " %08x & %08x", + DEV_PR_ARG, __entry->val, __entry->mask + ) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c new file mode 100644 index 000000000000..aea142600042 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2.h" +#include "../dma.h" + +void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76x2_dev *dev = hw->priv; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + + if (control->sta) { + struct mt76x02_sta *msta; + + msta = (struct mt76x02_sta *)control->sta->drv_priv; + wcid = &msta->wcid; + /* sw encrypted frames */ + if (!info->control.hw_key && wcid->hw_key_idx != 0xff) + control->sta = NULL; + } + + if (vif && !control->sta) { + struct mt76x02_vif *mvif; + + mvif = (struct mt76x02_vif *)vif->drv_priv; + wcid = &mvif->group_wcid; + } + + mt76_tx(&dev->mt76, control->sta, wcid, skb); +} +EXPORT_SYMBOL_GPL(mt76x2_tx); + +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, + const struct ieee80211_tx_rate *rate) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) mdev; + s8 max_txpwr; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + + if (mcs == 8 || mcs == 9) { + max_txpwr = mdev->rate_power.vht[8]; + } else { + u8 nss, idx; + + nss = ieee80211_rate_get_vht_nss(rate); + idx = ((nss - 1) << 3) + mcs; + max_txpwr = mdev->rate_power.ht[idx & 0xf]; + } + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + max_txpwr = mdev->rate_power.ht[rate->idx & 0xf]; + } else { + enum nl80211_band band = dev->mt76.chandef.chan->band; + + if (band == NL80211_BAND_2GHZ) { + const struct ieee80211_rate *r; + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + struct mt76_rate_power *rp = &mdev->rate_power; + + r = &wiphy->bands[band]->bitrates[rate->idx]; + if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) + max_txpwr = rp->cck[r->hw_value & 0x3]; + else + max_txpwr = rp->ofdm[r->hw_value & 0x7]; + } else { + max_txpwr = mdev->rate_power.ofdm[rate->idx & 0x7]; + } + } + + return max_txpwr; +} +EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj); + +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) +{ + txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); + txpwr -= (dev->target_power + dev->target_power_delta[0]); + txpwr = min_t(s8, txpwr, max_txpwr_adj); + + if (!dev->enable_tpc) + return 0; + else if (txpwr >= 0) + return min_t(s8, txpwr, 7); + else + return (txpwr < -16) ? 8 : (txpwr + 32) / 2; +} +EXPORT_SYMBOL_GPL(mt76x2_tx_get_txpwr_adj); + +void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) +{ + s8 txpwr_adj; + + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, + dev->mt76.rate_power.ofdm[4]); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); +} +EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c new file mode 100644 index 000000000000..b0c172107aae --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 +#include + +#include "../mt76x02_usb.h" +#include "mt76x2u.h" + +static const struct usb_device_id mt76x2u_device_table[] = { + { USB_DEVICE(0x0e8d, 0x7612) }, /* Alfa AWUS036ACM */ + { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ + { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ + { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ + { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USB-AC1200 */ + { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ + { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ + { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ + { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ + { }, +}; + +static int mt76x2u_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct mt76x2_dev *dev; + int err; + + dev = mt76x2u_alloc_device(&intf->dev); + if (!dev) + return -ENOMEM; + + udev = usb_get_dev(udev); + usb_reset_device(udev); + + mt76x02u_init_mcu(&dev->mt76); + err = mt76u_init(&dev->mt76, intf); + if (err < 0) + goto err; + + dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + + err = mt76x2u_register_device(dev); + if (err < 0) + goto err; + + return 0; + +err: + ieee80211_free_hw(mt76_hw(dev)); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + + return err; +} + +static void mt76x2u_disconnect(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct ieee80211_hw *hw = mt76_hw(dev); + + set_bit(MT76_REMOVED, &dev->mt76.state); + ieee80211_unregister_hw(hw); + mt76x2u_cleanup(dev); + + ieee80211_free_hw(hw); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); +} + +static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, + pm_message_t state) +{ + struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct mt76_usb *usb = &dev->mt76.usb; + + mt76u_stop_queues(&dev->mt76); + mt76x2u_stop_hw(dev); + usb_kill_urb(usb->mcu.res.urb); + + return 0; +} + +static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) +{ + struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct mt76_usb *usb = &dev->mt76.usb; + int err; + + reinit_completion(&usb->mcu.cmpl); + err = mt76u_submit_buf(&dev->mt76, USB_DIR_IN, + MT_EP_IN_CMD_RESP, + &usb->mcu.res, GFP_KERNEL, + mt76u_mcu_complete_urb, + &usb->mcu.cmpl); + if (err < 0) + goto err; + + err = mt76u_submit_rx_buffers(&dev->mt76); + if (err < 0) + goto err; + + tasklet_enable(&usb->rx_tasklet); + tasklet_enable(&usb->tx_tasklet); + + err = mt76x2u_init_hardware(dev); + if (err < 0) + goto err; + + return 0; + +err: + mt76x2u_cleanup(dev); + return err; +} + +MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); +MODULE_FIRMWARE(MT7662U_FIRMWARE); +MODULE_FIRMWARE(MT7662U_ROM_PATCH); + +static struct usb_driver mt76x2u_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76x2u_device_table, + .probe = mt76x2u_probe, + .disconnect = mt76x2u_disconnect, +#ifdef CONFIG_PM + .suspend = mt76x2u_suspend, + .resume = mt76x2u_resume, + .reset_resume = mt76x2u_resume, +#endif /* CONFIG_PM */ + .soft_unbind = 1, + .disable_hub_initiated_lpm = 1, +}; +module_usb_driver(mt76x2u_driver); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c new file mode 100644 index 000000000000..6eb7b28d102f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2u.h" +#include "../dma.h" +#include "../mt76x02_util.h" +#include "../mt76x02_usb.h" + +static int +mt76x2u_check_skb_rooms(struct sk_buff *skb) +{ + int hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u32 need_head; + + need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; + if (hdr_len % 4) + need_head += 2; + return skb_cow(skb, need_head); +} + +int mt76x2u_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 mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_txwi *txwi; + int err, len = skb->len; + + err = mt76x2u_check_skb_rooms(skb); + if (err < 0) + return -ENOMEM; + + mt76x02_insert_hdr_pad(skb); + + txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); + mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); + + return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c new file mode 100644 index 000000000000..55e0dea568b8 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 + +#include "mt76x2u.h" +#include "../mt76x02_util.h" +#include "../mt76x02_phy.h" +#include "eeprom.h" + +static void mt76x2u_init_dma(struct mt76x2_dev *dev) +{ + u32 val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); + + val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD | + 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_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); +} + +static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev) +{ + mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) | BIT(16)); + udelay(1); + + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1c), 0xff); + mt76_set(dev, MT_VEND_ADDR(CFG, 0x1c), 0x30); + + mt76_wr(dev, MT_VEND_ADDR(CFG, 0x14), 0x484f); + udelay(1); + + mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(17)); + usleep_range(150, 200); + + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(16)); + usleep_range(50, 100); + + mt76_set(dev, MT_VEND_ADDR(CFG, 0x14c), BIT(19) | BIT(20)); +} + +static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit) +{ + int shift = unit ? 8 : 0; + u32 val = (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift; + + /* Enable RF BG */ + mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) << shift); + usleep_range(10, 20); + + /* Enable RFDIG LDO/AFE/ABB/ADDA */ + mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), val); + usleep_range(10, 20); + + /* Switch RFDIG power to internal LDO */ + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(2) << shift); + usleep_range(10, 20); + + mt76x2u_power_on_rf_patch(dev); + + mt76_set(dev, 0x530, 0xf); +} + +static void mt76x2u_power_on(struct mt76x2_dev *dev) +{ + u32 val; + + /* Turn on WL MTCMOS */ + mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), + MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); + + val = MT_WLAN_MTC_CTRL_STATE_UP | + MT_WLAN_MTC_CTRL_PWR_ACK | + MT_WLAN_MTC_CTRL_PWR_ACK_S; + + mt76_poll(dev, MT_VEND_ADDR(CFG, 0x148), val, val, 1000); + + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0x7f << 16); + usleep_range(10, 20); + + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); + usleep_range(10, 20); + + mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xfff); + + /* Turn on AD/DA power down */ + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1204), BIT(3)); + + /* WLAN function enable */ + mt76_set(dev, MT_VEND_ADDR(CFG, 0x80), BIT(0)); + + /* Release BBP software reset */ + mt76_clear(dev, MT_VEND_ADDR(CFG, 0x64), BIT(18)); + + mt76x2u_power_on_rf(dev, 0); + mt76x2u_power_on_rf(dev, 1); +} + +static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) +{ + u32 val, i; + + dev->mt76.eeprom.data = devm_kzalloc(dev->mt76.dev, + MT7612U_EEPROM_SIZE, + GFP_KERNEL); + dev->mt76.eeprom.size = MT7612U_EEPROM_SIZE; + if (!dev->mt76.eeprom.data) + return -ENOMEM; + + for (i = 0; i + 4 <= MT7612U_EEPROM_SIZE; i += 4) { + val = mt76_rr(dev, MT_VEND_ADDR(EEPROM, i)); + put_unaligned_le32(val, dev->mt76.eeprom.data + i); + } + + mt76x02_eeprom_parse_hw_cap(&dev->mt76); + return 0; +} + +struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) +{ + static const struct mt76_driver_ops drv_ops = { + .tx_prepare_skb = mt76x2u_tx_prepare_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, + .tx_status_data = mt76x02_tx_status_data, + .rx_skb = mt76x2_queue_rx_skb, + }; + struct mt76x2_dev *dev; + struct mt76_dev *mdev; + + mdev = mt76_alloc_device(sizeof(*dev), &mt76x2u_ops); + if (!mdev) + return NULL; + + dev = container_of(mdev, struct mt76x2_dev, mt76); + mdev->dev = pdev; + mdev->drv = &drv_ops; + + return dev; +} + +static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) +{ + mt76_wr(dev, MT_BCN_OFFSET(0), 0x18100800); + mt76_wr(dev, MT_BCN_OFFSET(1), 0x38302820); + mt76_wr(dev, MT_BCN_OFFSET(2), 0x58504840); + mt76_wr(dev, MT_BCN_OFFSET(3), 0x78706860); +} + +int mt76x2u_init_hardware(struct mt76x2_dev *dev) +{ + const struct mt76_wcid_addr addr = { + .macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .ba_mask = 0, + }; + int i, err; + + mt76x2_reset_wlan(dev, true); + mt76x2u_power_on(dev); + + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + err = mt76x2u_mcu_fw_init(dev); + if (err < 0) + return err; + + 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; + + /* wait for asic ready after fw load. */ + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0); + mt76_wr(dev, MT_TSO_CTRL, 0); + + mt76x2u_init_dma(dev); + + err = mt76x2u_mcu_init(dev); + if (err < 0) + return err; + + err = mt76x2u_mac_reset(dev); + if (err < 0) + return err; + + mt76x02_mac_setaddr(&dev->mt76, + dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + + mt76x2u_init_beacon_offsets(dev); + + if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) + return -ETIMEDOUT; + + /* reset wcid table */ + for (i = 0; i < 254; i++) + mt76_wr_copy(dev, MT_WCID_ADDR(i), &addr, + sizeof(struct mt76_wcid_addr)); + + /* reset shared key table and pairwise key table */ + for (i = 0; i < 4; i++) + mt76_wr(dev, MT_SKEY_MODE_BASE_0 + 4 * i, 0); + for (i = 0; i < 256; i++) + mt76_wr(dev, MT_WCID_ATTR(i), 1); + + 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); + + mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); + mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f); + + err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); + if (err < 0) + return err; + + mt76x02_phy_set_rxpath(&dev->mt76); + mt76x02_phy_set_txdac(&dev->mt76); + + return mt76x2u_mac_stop(dev); +} + +int mt76x2u_register_device(struct mt76x2_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + int err; + + INIT_DELAYED_WORK(&dev->cal_work, mt76x2u_phy_calibrate); + mt76x2_init_device(dev); + + err = mt76x2u_init_eeprom(dev); + if (err < 0) + return err; + + err = mt76u_alloc_queues(&dev->mt76); + if (err < 0) + goto fail; + + err = mt76u_mcu_init_rx(&dev->mt76); + if (err < 0) + return err; + + err = mt76x2u_init_hardware(dev); + if (err < 0) + goto fail; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + err = mt76_register_device(&dev->mt76, true, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); + if (err) + goto fail; + + /* check hw sg support in order to enable AMSDU */ + if (mt76u_check_sg(&dev->mt76)) + hw->max_tx_fragments = MT_SG_MAX_SIZE; + else + hw->max_tx_fragments = 1; + + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + + mt76x2_init_debugfs(dev); + mt76x2_init_txpower(dev, &dev->mt76.sband_2g.sband); + mt76x2_init_txpower(dev, &dev->mt76.sband_5g.sband); + + return 0; + +fail: + mt76x2u_cleanup(dev); + return err; +} + +void mt76x2u_stop_hw(struct mt76x2_dev *dev) +{ + mt76u_stop_stat_wk(&dev->mt76); + cancel_delayed_work_sync(&dev->cal_work); + mt76x2u_mac_stop(dev); +} + +void mt76x2u_cleanup(struct mt76x2_dev *dev) +{ + mt76x02_mcu_set_radio_state(&dev->mt76, false, false); + mt76x2u_stop_hw(dev); + mt76u_queues_deinit(&dev->mt76); + mt76u_mcu_deinit(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c new file mode 100644 index 000000000000..ae89461f803c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2u.h" +#include "eeprom.h" + +static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev) +{ + mt76_rr(dev, MT_RX_STAT_0); + mt76_rr(dev, MT_RX_STAT_1); + mt76_rr(dev, MT_RX_STAT_2); + mt76_rr(dev, MT_TX_STA_0); + mt76_rr(dev, MT_TX_STA_1); + mt76_rr(dev, MT_TX_STA_2); +} + +static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) +{ + s8 offset = 0; + u16 eep_val; + + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); + + offset = eep_val & 0x7f; + if ((eep_val & 0xff) == 0xff) + offset = 0; + else if (eep_val & 0x80) + offset = 0 - offset; + + eep_val >>= 8; + if (eep_val == 0x00 || eep_val == 0xff) { + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); + eep_val &= 0xff; + + if (eep_val == 0x00 || eep_val == 0xff) + eep_val = 0x14; + } + + eep_val &= 0x7f; + mt76_rmw_field(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL5), + MT_XO_CTRL5_C2_VAL, eep_val + offset); + mt76_set(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL6), MT_XO_CTRL6_C2_CTRL); + + mt76_wr(dev, 0x504, 0x06000000); + mt76_wr(dev, 0x50c, 0x08800000); + mdelay(5); + mt76_wr(dev, 0x504, 0x0); + + /* decrease SIFS from 16us to 13us */ + mt76_rmw_field(dev, MT_XIFS_TIME_CFG, + MT_XIFS_TIME_CFG_OFDM_SIFS, 0xd); + mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, MT_BKOFF_SLOT_CFG_CC_DELAY, 1); + + /* init fce */ + mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); + + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { + case 0: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); + break; + case 1: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); + break; + default: + break; + } +} + +int mt76x2u_mac_reset(struct mt76x2_dev *dev) +{ + mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5)); + + /* init pbf regs */ + mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); + mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); + + mt76_write_mac_initvals(dev); + + mt76_wr(dev, MT_TX_LINK_CFG, 0x1020); + mt76_wr(dev, MT_AUTO_RSP_CFG, 0x13); + mt76_wr(dev, MT_MAX_LEN_CFG, 0x2f00); + mt76_wr(dev, MT_TX_RTS_CFG, 0x92b20); + + mt76_wr(dev, MT_WMM_AIFSN, 0x2273); + mt76_wr(dev, MT_WMM_CWMIN, 0x2344); + mt76_wr(dev, MT_WMM_CWMAX, 0x34aa); + + mt76_clear(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP); + + if (is_mt7612(dev)) + mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); + + mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); + mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); + + mt76x2u_mac_fixup_xtal(dev); + + return 0; +} + +int mt76x2u_mac_start(struct mt76x2_dev *dev) +{ + mt76x2u_mac_reset_counters(dev); + + mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + mt76x02_wait_for_wpdma(&dev->mt76, 1000); + usleep_range(50, 100); + + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); + + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + + return 0; +} + +int mt76x2u_mac_stop(struct mt76x2_dev *dev) +{ + int i, count = 0, val; + bool stopped = false; + u32 rts_cfg; + + if (test_bit(MT76_REMOVED, &dev->mt76.state)) + return -EIO; + + rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); + + mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); + mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); + + /* wait tx dma to stop */ + for (i = 0; i < 2000; i++) { + val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); + if (!(val & MT_USB_DMA_CFG_TX_BUSY) && i > 10) + break; + usleep_range(50, 100); + } + + /* page count on TxQ */ + for (i = 0; i < 200; i++) { + if (!(mt76_rr(dev, 0x0438) & 0xffffffff) && + !(mt76_rr(dev, 0x0a30) & 0x000000ff) && + !(mt76_rr(dev, 0x0a34) & 0xff00ff00)) + break; + usleep_range(10, 20); + } + + /* disable tx-rx */ + mt76_clear(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_RX | + MT_MAC_SYS_CTRL_ENABLE_TX); + + /* Wait for MAC to become idle */ + for (i = 0; i < 1000; i++) { + if (!(mt76_rr(dev, MT_MAC_STATUS) & MT_MAC_STATUS_TX) && + !mt76_rr(dev, MT_BBP(IBI, 12))) { + stopped = true; + break; + } + usleep_range(10, 20); + } + + if (!stopped) { + mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); + + mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); + } + + /* page count on RxQ */ + for (i = 0; i < 200; i++) { + if (!(mt76_rr(dev, 0x0430) & 0x00ff0000) && + !(mt76_rr(dev, 0x0a30) & 0xffffffff) && + !(mt76_rr(dev, 0x0a34) & 0xffffffff) && + ++count > 10) + break; + msleep(50); + } + + if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 2000)) + dev_warn(dev->mt76.dev, "MAC RX failed to stop\n"); + + /* wait rx dma to stop */ + for (i = 0; i < 2000; i++) { + val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); + if (!(val & MT_USB_DMA_CFG_RX_BUSY) && i > 10) + break; + usleep_range(50, 100); + } + + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); + + return 0; +} + +void mt76x2u_mac_resume(struct mt76x2_dev *dev) +{ + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20)); + mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1)); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c new file mode 100644 index 000000000000..26f1c04ea448 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2u.h" +#include "../mt76x02_util.h" + +static int mt76x2u_start(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mt76.mutex); + + ret = mt76x2u_mac_start(dev); + if (ret) + goto out; + + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + +out: + mutex_unlock(&dev->mt76.mutex); + return ret; +} + +static void mt76x2u_stop(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x2u_stop_hw(dev); + mutex_unlock(&dev->mt76.mutex); +} + +static int mt76x2u_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) + mt76x02_mac_setaddr(&dev->mt76, vif->addr); + + mt76x02_vif_init(&dev->mt76, vif, 0); + return 0; +} + +static int +mt76x2u_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef) +{ + int err; + + cancel_delayed_work_sync(&dev->cal_work); + set_bit(MT76_RESET, &dev->mt76.state); + + mt76_set_channel(&dev->mt76); + + mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); + mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); + mt76x2_mac_stop(dev, false); + + err = mt76x2u_phy_set_channel(dev, chandef); + + mt76x2u_mac_resume(dev); + + clear_bit(MT76_RESET, &dev->mt76.state); + mt76_txq_schedule_all(&dev->mt76); + + return err; +} + +static void +mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + + if (changed & BSS_CHANGED_ASSOC) { + mt76x2u_phy_channel_calibrate(dev); + mt76x2_apply_gain_adj(dev); + } + + if (changed & BSS_CHANGED_BSSID) { + mt76_wr(dev, MT_MAC_BSSID_DW0, + get_unaligned_le32(info->bssid)); + mt76_wr(dev, MT_MAC_BSSID_DW1, + get_unaligned_le16(info->bssid + 4)); + } + + mutex_unlock(&dev->mt76.mutex); +} + +static int +mt76x2u_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + int err = 0; + + mutex_lock(&dev->mt76.mutex); + + 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); + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + err = mt76x2u_set_channel(dev, &hw->conf.chandef); + ieee80211_wake_queues(hw); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + dev->mt76.txpower_conf = hw->conf.power_level * 2; + + /* convert to per-chain power for 2x2 devices */ + dev->mt76.txpower_conf -= 6; + + if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + mt76x2_phy_set_txpower(dev); + } + + mutex_unlock(&dev->mt76.mutex); + + return err; +} + +static void +mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac) +{ + struct mt76x2_dev *dev = hw->priv; + + set_bit(MT76_SCANNING, &dev->mt76.state); +} + +static void +mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + clear_bit(MT76_SCANNING, &dev->mt76.state); +} + +const struct ieee80211_ops mt76x2u_ops = { + .tx = mt76x2_tx, + .start = mt76x2u_start, + .stop = mt76x2u_stop, + .add_interface = mt76x2u_add_interface, + .remove_interface = mt76x02_remove_interface, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, + .set_key = mt76x02_set_key, + .ampdu_action = mt76x02_ampdu_action, + .config = mt76x2u_config, + .wake_tx_queue = mt76_wake_tx_queue, + .bss_info_changed = mt76x2u_bss_info_changed, + .configure_filter = mt76x02_configure_filter, + .conf_tx = mt76x02_conf_tx, + .sw_scan_start = mt76x2u_sw_scan, + .sw_scan_complete = mt76x2u_sw_scan_complete, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c new file mode 100644 index 000000000000..35e157be456c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 + +#include "mt76x2u.h" +#include "eeprom.h" +#include "../mt76x02_usb.h" + +#define MT_CMD_HDR_LEN 4 + +#define MCU_FW_URB_MAX_PAYLOAD 0x3900 +#define MCU_ROM_PATCH_MAX_PAYLOAD 2048 + +#define MT76U_MCU_ILM_OFFSET 0x80000 +#define MT76U_MCU_DLM_OFFSET 0x110000 +#define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 + +int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, + bool ext, int rssi, u32 false_cca) +{ + struct { + __le32 channel; + __le32 rssi_val; + __le32 false_cca_val; + } __packed __aligned(4) msg = { + .rssi_val = cpu_to_le32(rssi), + .false_cca_val = cpu_to_le32(false_cca), + }; + struct sk_buff *skb; + u32 val = channel; + + if (ap) + val |= BIT(31); + if (ext) + val |= BIT(30); + msg.channel = cpu_to_le32(val); + + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); +} + +static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev) +{ + mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x12, 0, NULL, 0); +} + +static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev) +{ + struct mt76_usb *usb = &dev->mt76.usb; + const u8 data[] = { + 0x6f, 0xfc, 0x08, 0x01, + 0x20, 0x04, 0x00, 0x00, + 0x00, 0x09, 0x00, + }; + + memcpy(usb->data, data, sizeof(data)); + mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_CLASS, + 0x12, 0, usb->data, sizeof(data)); +} + +static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev) +{ + struct mt76_usb *usb = &dev->mt76.usb; + u8 data[] = { + 0x6f, 0xfc, 0x05, 0x01, + 0x07, 0x01, 0x00, 0x04 + }; + + memcpy(usb->data, data, sizeof(data)); + mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_CLASS, + 0x12, 0, usb->data, sizeof(data)); +} + +static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) +{ + bool rom_protect = !is_mt7612(dev); + struct mt76x02_patch_header *hdr; + u32 val, patch_mask, patch_reg; + const struct firmware *fw; + int err; + + if (rom_protect && + !mt76_poll_msec(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { + dev_err(dev->mt76.dev, + "could not get hardware semaphore for ROM PATCH\n"); + return -ETIMEDOUT; + } + + if (mt76xx_rev(dev) >= MT76XX_REV_E3) { + patch_mask = BIT(0); + patch_reg = MT_MCU_CLOCK_CTL; + } else { + patch_mask = BIT(1); + patch_reg = MT_MCU_COM_REG0; + } + + if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { + dev_info(dev->mt76.dev, "ROM patch already applied\n"); + return 0; + } + + err = request_firmware(&fw, MT7662U_ROM_PATCH, dev->mt76.dev); + if (err < 0) + return err; + + if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { + dev_err(dev->mt76.dev, "failed to load firmware\n"); + err = -EIO; + goto out; + } + + hdr = (struct mt76x02_patch_header *)fw->data; + dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); + + /* enable USB_DMA_CFG */ + val = 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); + mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); + + /* vendor reset */ + mt76x02u_mcu_fw_reset(&dev->mt76); + usleep_range(5000, 10000); + + /* enable FCE to send in-band cmd */ + mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); + /* 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, 0x1); + /* FCE pdma enable */ + mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + /* FCE skip_fs_en */ + mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); + + err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + fw->size - sizeof(*hdr), + MCU_ROM_PATCH_MAX_PAYLOAD, + MT76U_MCU_ROM_PATCH_OFFSET); + if (err < 0) { + err = -EIO; + goto out; + } + + mt76x2u_mcu_enable_patch(dev); + mt76x2u_mcu_reset_wmt(dev); + mdelay(20); + + if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 100)) { + dev_err(dev->mt76.dev, "failed to load ROM patch\n"); + err = -ETIMEDOUT; + } + +out: + if (rom_protect) + mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); + release_firmware(fw); + return err; +} + +static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) +{ + u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET; + const struct mt76x02_fw_header *hdr; + int err, len, ilm_len, dlm_len; + const struct firmware *fw; + + err = request_firmware(&fw, MT7662U_FIRMWARE, dev->mt76.dev); + if (err < 0) + return err; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + err = -EINVAL; + goto out; + } + + hdr = (const struct mt76x02_fw_header *)fw->data; + ilm_len = le32_to_cpu(hdr->ilm_len); + dlm_len = le32_to_cpu(hdr->dlm_len); + len = sizeof(*hdr) + ilm_len + dlm_len; + if (fw->size != len) { + err = -EINVAL; + goto out; + } + + 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->build_ver); + dev_info(dev->mt76.dev, "Build: %x\n", val); + dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); + + /* vendor reset */ + mt76x02u_mcu_fw_reset(&dev->mt76); + usleep_range(5000, 10000); + + /* enable USB_DMA_CFG */ + val = 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); + mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); + /* enable FCE to send in-band cmd */ + mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); + /* 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, 0x1); + /* FCE pdma enable */ + mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + /* FCE skip_fs_en */ + mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); + + /* load ILM */ + err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + ilm_len, MCU_FW_URB_MAX_PAYLOAD, + MT76U_MCU_ILM_OFFSET); + if (err < 0) { + err = -EIO; + goto out; + } + + /* load DLM */ + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + dlm_offset += 0x800; + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw->data + sizeof(*hdr) + ilm_len, + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + dlm_offset); + if (err < 0) { + err = -EIO; + goto out; + } + + mt76x2u_mcu_load_ivb(dev); + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 100)) { + dev_err(dev->mt76.dev, "firmware failed to start\n"); + err = -ETIMEDOUT; + goto out; + } + + mt76_set(dev, MT_MCU_COM_REG0, BIT(1)); + /* enable FCE to send in-band cmd */ + mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); + dev_dbg(dev->mt76.dev, "firmware running\n"); + mt76x02_set_ethtool_fwver(&dev->mt76, hdr); + +out: + release_firmware(fw); + return err; +} + +int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev) +{ + int err; + + err = mt76x2u_mcu_load_rom_patch(dev); + if (err < 0) + return err; + + return mt76x2u_mcu_load_firmware(dev); +} + +int mt76x2u_mcu_init(struct mt76x2_dev *dev) +{ + int err; + + err = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, + 1, false); + if (err < 0) + return err; + + return mt76x02_mcu_set_radio_state(&dev->mt76, true, false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c new file mode 100644 index 000000000000..9dd1943a71bb --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * 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 "mt76x2u.h" +#include "eeprom.h" + +void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + bool is_5ghz = chan->band == NL80211_BAND_5GHZ; + + if (mt76x2_channel_silent(dev)) + return; + + mt76x2u_mac_stop(dev); + + if (is_5ghz) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, false); + + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, false); + + mt76x2u_mac_resume(dev); +} + +static void +mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) +{ + u8 channel = dev->mt76.chandef.chan->hw_value; + int freq, freq1; + u32 false_cca; + + freq = dev->mt76.chandef.chan->center_freq; + freq1 = dev->mt76.chandef.center_freq1; + + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: { + int ch_group_index; + + ch_group_index = (freq - freq1 + 30) / 20; + if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) + ch_group_index = 0; + channel += 6 - ch_group_index * 4; + break; + } + case NL80211_CHAN_WIDTH_40: + if (freq1 > freq) + channel += 2; + else + channel -= 2; + break; + default: + break; + } + + dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); + false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, + mt76_rr(dev, MT_RX_STAT_1)); + + mt76x2u_mcu_set_dynamic_vga(dev, channel, false, false, + dev->cal.avg_rssi_all, false_cca); +} + +void mt76x2u_phy_calibrate(struct work_struct *work) +{ + struct mt76x2_dev *dev; + + dev = container_of(work, struct mt76x2_dev, cal_work.work); + mt76x2_phy_tssi_compensate(dev, false); + mt76x2u_phy_update_channel_gain(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); +} + +int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef) +{ + u32 ext_cca_chan[4] = { + [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(0)), + [1] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(1)), + [2] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(2)), + [3] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(3)), + }; + bool scan = test_bit(MT76_SCANNING, &dev->mt76.state); + struct ieee80211_channel *chan = chandef->chan; + u8 channel = chan->hw_value, bw, bw_index; + int ch_group_index, freq, freq1, ret; + + dev->cal.channel_cal_done = false; + freq = chandef->chan->center_freq; + freq1 = chandef->center_freq1; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + bw = 1; + if (freq1 > freq) { + bw_index = 1; + ch_group_index = 0; + } else { + bw_index = 3; + ch_group_index = 1; + } + channel += 2 - ch_group_index * 4; + break; + case NL80211_CHAN_WIDTH_80: + ch_group_index = (freq - freq1 + 30) / 20; + if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) + ch_group_index = 0; + bw = 2; + bw_index = ch_group_index; + channel += 6 - ch_group_index * 4; + break; + default: + bw = 0; + bw_index = 0; + ch_group_index = 0; + break; + } + + mt76x2_read_rx_gain(dev); + mt76x2_phy_set_txpower_regs(dev, chan->band); + mt76x2_configure_tx_delay(dev, chan->band, bw); + mt76x2_phy_set_txpower(dev); + + mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); + mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); + + mt76_rmw(dev, MT_EXT_CCA_CFG, + (MT_EXT_CCA_CFG_CCA0 | + MT_EXT_CCA_CFG_CCA1 | + MT_EXT_CCA_CFG_CCA2 | + MT_EXT_CCA_CFG_CCA3 | + MT_EXT_CCA_CFG_CCA_MASK), + ext_cca_chan[ch_group_index]); + + ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); + if (ret) + return ret; + + mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); + + /* Enable LDPC Rx */ + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); + + if (!dev->cal.init_cal_done) { + u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); + + if (val != 0xff) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, + 0, false); + } + + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, false); + + /* Rx LPF calibration */ + if (!dev->cal.init_cal_done) + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, false); + dev->cal.init_cal_done = true; + + mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2); + mt76_wr(dev, MT_BBP(AGC, 7), 0x08081010); + mt76_wr(dev, MT_BBP(AGC, 11), 0x00000404); + mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); + mt76_wr(dev, MT_TXOP_CTRL_CFG, 0X04101b3f); + + mt76_set(dev, MT_BBP(TXO, 4), BIT(25)); + mt76_set(dev, MT_BBP(RXO, 13), BIT(8)); + + if (scan) + return 0; + + if (mt76x02_tssi_enabled(&dev->mt76)) { + /* init default values for temp compensation */ + mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + 0x38); + mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, + 0x38); + + /* init tssi calibration */ + if (!mt76x2_channel_silent(dev)) { + struct ieee80211_channel *chan; + u32 flag = 0; + + chan = dev->mt76.chandef.chan; + if (chan->band == NL80211_BAND_5GHZ) + flag |= BIT(0); + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + flag |= BIT(8); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, + flag, false); + dev->cal.tssi_cal_done = true; + } + } + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c deleted file mode 100644 index 3e667d8c0ee7..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "mt76x02_mac.h" - -void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - void *rxwi = skb->data; - - if (q == MT_RXQ_MCU) { - /* this is used just by mmio code */ - skb_queue_tail(&mdev->mmio.mcu.res_q, skb); - wake_up(&mdev->mmio.mcu.wait); - return; - } - - skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (mt76x2_mac_process_rx(dev, skb, rxwi)) { - dev_kfree_skb(skb); - return; - } - - mt76_rx(&dev->mt76, q, skb); -} -EXPORT_SYMBOL_GPL(mt76x2_queue_rx_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c deleted file mode 100644 index 06e47f960f9a..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include "mt76x2.h" -#include "mt76x2_trace.h" -#include "mt76x02_util.h" - -void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) -{ - mt76x02_irq_enable(mdev, MT_INT_RX_DONE(q)); -} - -irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) -{ - struct mt76x2_dev *dev = dev_instance; - u32 intr; - - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); - - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) - return IRQ_NONE; - - trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask); - - intr &= dev->mt76.mmio.irqmask; - - if (intr & MT_INT_TX_DONE_ALL) { - mt76x02_irq_disable(&dev->mt76, MT_INT_TX_DONE_ALL); - tasklet_schedule(&dev->tx_tasklet); - } - - if (intr & MT_INT_RX_DONE(0)) { - mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(0)); - napi_schedule(&dev->mt76.napi[0]); - } - - if (intr & MT_INT_RX_DONE(1)) { - mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(1)); - napi_schedule(&dev->mt76.napi[1]); - } - - if (intr & MT_INT_PRE_TBTT) - tasklet_schedule(&dev->pre_tbtt_tasklet); - - /* send buffered multicast frames now */ - if (intr & MT_INT_TBTT) - mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); - - if (intr & MT_INT_TX_STAT) { - mt76x2_mac_poll_tx_status(dev, true); - tasklet_schedule(&dev->tx_tasklet); - } - - if (intr & MT_INT_GPTIMER) { - mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); - tasklet_schedule(&dev->dfs_pd.dfs_tasklet); - } - - return IRQ_HANDLED; -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c deleted file mode 100644 index ea373bae1522..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include "mt76x2.h" - -static int -mt76x2_ampdu_stat_read(struct seq_file *file, void *data) -{ - struct mt76x2_dev *dev = file->private; - int i, j; - - for (i = 0; i < 4; i++) { - seq_puts(file, "Length: "); - for (j = 0; j < 8; j++) - seq_printf(file, "%8d | ", i * 8 + j + 1); - seq_puts(file, "\n"); - seq_puts(file, "Count: "); - for (j = 0; j < 8; j++) - seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); - seq_puts(file, "\n"); - seq_puts(file, "--------"); - for (j = 0; j < 8; j++) - seq_puts(file, "-----------"); - seq_puts(file, "\n"); - } - - return 0; -} - -static int -mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) -{ - return single_open(f, mt76x2_ampdu_stat_read, inode->i_private); -} - -static int read_txpower(struct seq_file *file, void *data) -{ - struct mt76x2_dev *dev = dev_get_drvdata(file->private); - - seq_printf(file, "Target power: %d\n", dev->target_power); - - mt76_seq_puts_array(file, "Delta", dev->target_power_delta, - ARRAY_SIZE(dev->target_power_delta)); - return 0; -} - -static const struct file_operations fops_ampdu_stat = { - .open = mt76x2_ampdu_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int -mt76x2_dfs_stat_read(struct seq_file *file, void *data) -{ - int i; - struct mt76x2_dev *dev = file->private; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - seq_printf(file, "allocated sequences:\t%d\n", - dfs_pd->seq_stats.seq_pool_len); - seq_printf(file, "used sequences:\t\t%d\n", - dfs_pd->seq_stats.seq_len); - seq_puts(file, "\n"); - - for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { - seq_printf(file, "engine: %d\n", i); - seq_printf(file, " hw pattern detected:\t%d\n", - dfs_pd->stats[i].hw_pattern); - seq_printf(file, " hw pulse discarded:\t%d\n", - dfs_pd->stats[i].hw_pulse_discarded); - seq_printf(file, " sw pattern detected:\t%d\n", - dfs_pd->stats[i].sw_pattern); - } - - return 0; -} - -static int -mt76x2_dfs_stat_open(struct inode *inode, struct file *f) -{ - return single_open(f, mt76x2_dfs_stat_read, inode->i_private); -} - -static const struct file_operations fops_dfs_stat = { - .open = mt76x2_dfs_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int read_agc(struct seq_file *file, void *data) -{ - struct mt76x2_dev *dev = dev_get_drvdata(file->private); - - seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); - seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); - seq_printf(file, "false_cca: %d\n", dev->cal.false_cca); - seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust); - - return 0; -} - -void mt76x2_init_debugfs(struct mt76x2_dev *dev) -{ - struct dentry *dir; - - dir = mt76_register_debugfs(&dev->mt76); - if (!dir) - return; - - debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); - debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); - - debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); - debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat); - debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, - read_txpower); - - debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); -} -EXPORT_SYMBOL_GPL(mt76x2_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c deleted file mode 100644 index 8cfa3a063bda..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * Copyright (C) 2016 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "mt76x02_util.h" - -#define RADAR_SPEC(m, len, el, eh, wl, wh, \ - w_tolerance, tl, th, t_tolerance, \ - bl, bh, event_exp, power_jmp) \ -{ \ - .mode = m, \ - .avg_len = len, \ - .e_low = el, \ - .e_high = eh, \ - .w_low = wl, \ - .w_high = wh, \ - .w_margin = w_tolerance, \ - .t_low = tl, \ - .t_high = th, \ - .t_margin = t_tolerance, \ - .b_low = bl, \ - .b_high = bh, \ - .event_expiration = event_exp, \ - .pwr_jmp = power_jmp \ -} - -static const struct mt76x2_radar_specs etsi_radar_specs[] = { - /* 20MHz */ - RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, - 0x7fffffff, 0x155cc0, 0x19dd), - RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, - 0x7fffffff, 0x2191c0, 0x15cc), - /* 40MHz */ - RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, - 0x7fffffff, 0x155cc0, 0x19dd), - RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, - 0x7fffffff, 0x2191c0, 0x15cc), - /* 80MHz */ - RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, - 0x7fffffff, 0x155cc0, 0x19cc), - RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, - 0x7fffffff, 0x155cc0, 0x19dd), - RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, - 0x7fffffff, 0x2191c0, 0x15cc) -}; - -static const struct mt76x2_radar_specs fcc_radar_specs[] = { - /* 20MHz */ - RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, - 0x7fffffff, 0xfe808, 0x13dc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0xfe808, 0x19dd), - RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0xfe808, 0x12cc), - RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0x57bcf00, 0x1289), - /* 40MHz */ - RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, - 0x7fffffff, 0xfe808, 0x13dc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0xfe808, 0x19dd), - RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0xfe808, 0x12cc), - RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0x57bcf00, 0x1289), - /* 80MHz */ - RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0, - 0x7fffffff, 0xfe808, 0x16cc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0xfe808, 0x19dd), - RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0xfe808, 0x12cc), - RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0x57bcf00, 0x1289) -}; - -static const struct mt76x2_radar_specs jp_w56_radar_specs[] = { - /* 20MHz */ - RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, - 0x7fffffff, 0x14c080, 0x13dc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0x14c080, 0x19dd), - RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0x14c080, 0x12cc), - RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0X57bcf00, 0x1289), - /* 40MHz */ - RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, - 0x7fffffff, 0x14c080, 0x13dc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0x14c080, 0x19dd), - RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0x14c080, 0x12cc), - RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0X57bcf00, 0x1289), - /* 80MHz */ - RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0, - 0x7fffffff, 0x14c080, 0x16cc), - RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, - 0x7fffffff, 0x14c080, 0x19dd), - RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, - 0x7fffffff, 0x14c080, 0x12cc), - RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, - 0x3938700, 0X57bcf00, 0x1289) -}; - -static const struct mt76x2_radar_specs jp_w53_radar_specs[] = { - /* 20MHz */ - RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 }, - RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 }, - /* 40MHz */ - RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 }, - RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 }, - /* 80MHz */ - RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 }, - RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, - 0x7fffffff, 0x14c080, 0x16cc), - { 0 } -}; - -static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, - u8 enable) -{ - u32 data; - - data = (1 << 1) | enable; - mt76_wr(dev, MT_BBP(DFS, 36), data); -} - -static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev, - struct mt76x2_dfs_sequence *seq) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - list_add(&seq->head, &dfs_pd->seq_pool); - - dfs_pd->seq_stats.seq_pool_len++; - dfs_pd->seq_stats.seq_len--; -} - -static -struct mt76x2_dfs_sequence *mt76x2_dfs_seq_pool_get(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq; - - if (list_empty(&dfs_pd->seq_pool)) { - seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); - } else { - seq = list_first_entry(&dfs_pd->seq_pool, - struct mt76x2_dfs_sequence, - head); - list_del(&seq->head); - dfs_pd->seq_stats.seq_pool_len--; - } - if (seq) - dfs_pd->seq_stats.seq_len++; - - return seq; -} - -static int mt76x2_dfs_get_multiple(int val, int frac, int margin) -{ - int remainder, factor; - - if (!frac) - return 0; - - if (abs(val - frac) <= margin) - return 1; - - factor = val / frac; - remainder = val % frac; - - if (remainder > margin) { - if ((frac - remainder) <= margin) - factor++; - else - factor = 0; - } - return factor; -} - -static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq, *tmp_seq; - int i; - - /* reset hw detector */ - mt76_wr(dev, MT_BBP(DFS, 1), 0xf); - - /* reset sw detector */ - for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { - dfs_pd->event_rb[i].h_rb = 0; - dfs_pd->event_rb[i].t_rb = 0; - } - - list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { - list_del_init(&seq->head); - mt76x2_dfs_seq_pool_put(dev, seq); - } -} - -static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) -{ - bool ret = false; - u32 current_ts, delta_ts; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); - delta_ts = current_ts - dfs_pd->chirp_pulse_ts; - dfs_pd->chirp_pulse_ts = current_ts; - - /* 12 sec */ - if (delta_ts <= (12 * (1 << 20))) { - if (++dfs_pd->chirp_pulse_cnt > 8) - ret = true; - } else { - dfs_pd->chirp_pulse_cnt = 1; - } - - return ret; -} - -static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev, - struct mt76x2_dfs_hw_pulse *pulse) -{ - u32 data; - - /* select channel */ - data = (MT_DFS_CH_EN << 16) | pulse->engine; - mt76_wr(dev, MT_BBP(DFS, 0), data); - - /* reported period */ - pulse->period = mt76_rr(dev, MT_BBP(DFS, 19)); - - /* reported width */ - pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20)); - pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23)); - - /* reported burst number */ - pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); -} - -static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, - struct mt76x2_dfs_hw_pulse *pulse) -{ - bool ret = false; - - if (!pulse->period || !pulse->w1) - return false; - - switch (dev->dfs_pd.region) { - case NL80211_DFS_FCC: - if (pulse->engine > 3) - break; - - if (pulse->engine == 3) { - ret = mt76x2_dfs_check_chirp(dev); - break; - } - - /* check short pulse*/ - if (pulse->w1 < 120) - ret = (pulse->period >= 2900 && - (pulse->period <= 4700 || - pulse->period >= 6400) && - (pulse->period <= 6800 || - pulse->period >= 10200) && - pulse->period <= 61600); - else if (pulse->w1 < 130) /* 120 - 130 */ - ret = (pulse->period >= 2900 && - pulse->period <= 61600); - else - ret = (pulse->period >= 3500 && - pulse->period <= 10100); - break; - case NL80211_DFS_ETSI: - if (pulse->engine >= 3) - break; - - ret = (pulse->period >= 4900 && - (pulse->period <= 10200 || - pulse->period >= 12400) && - pulse->period <= 100100); - break; - case NL80211_DFS_JP: - if (dev->mt76.chandef.chan->center_freq >= 5250 && - dev->mt76.chandef.chan->center_freq <= 5350) { - /* JPW53 */ - if (pulse->w1 <= 130) - ret = (pulse->period >= 28360 && - (pulse->period <= 28700 || - pulse->period >= 76900) && - pulse->period <= 76940); - break; - } - - if (pulse->engine > 3) - break; - - if (pulse->engine == 3) { - ret = mt76x2_dfs_check_chirp(dev); - break; - } - - /* check short pulse*/ - if (pulse->w1 < 120) - ret = (pulse->period >= 2900 && - (pulse->period <= 4700 || - pulse->period >= 6400) && - (pulse->period <= 6800 || - pulse->period >= 27560) && - (pulse->period <= 27960 || - pulse->period >= 28360) && - (pulse->period <= 28700 || - pulse->period >= 79900) && - pulse->period <= 80100); - else if (pulse->w1 < 130) /* 120 - 130 */ - ret = (pulse->period >= 2900 && - (pulse->period <= 10100 || - pulse->period >= 27560) && - (pulse->period <= 27960 || - pulse->period >= 28360) && - (pulse->period <= 28700 || - pulse->period >= 79900) && - pulse->period <= 80100); - else - ret = (pulse->period >= 3900 && - pulse->period <= 10100); - break; - case NL80211_DFS_UNSET: - default: - return false; - } - - return ret; -} - -static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) -{ - u32 data; - - /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2) - * 2nd: DFS_R37[21:0]: pulse time - * 3rd: DFS_R37[11:0]: pulse width - * 3rd: DFS_R37[25:16]: phase - * 4th: DFS_R37[12:0]: current pwr - * 4th: DFS_R37[21:16]: pwr stable counter - * - * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected - */ - data = mt76_rr(dev, MT_BBP(DFS, 37)); - if (!MT_DFS_CHECK_EVENT(data)) - return false; - - event->engine = MT_DFS_EVENT_ENGINE(data); - data = mt76_rr(dev, MT_BBP(DFS, 37)); - event->ts = MT_DFS_EVENT_TIMESTAMP(data); - data = mt76_rr(dev, MT_BBP(DFS, 37)); - event->width = MT_DFS_EVENT_WIDTH(data); - - return true; -} - -static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) -{ - if (event->engine == 2) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; - u16 last_event_idx; - u32 delta_ts; - - last_event_idx = mt76_decr(event_buff->t_rb, - MT_DFS_EVENT_BUFLEN); - delta_ts = event->ts - event_buff->data[last_event_idx].ts; - if (delta_ts < MT_DFS_EVENT_TIME_MARGIN && - event_buff->data[last_event_idx].width >= 200) - return false; - } - return true; -} - -static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff; - - /* add radar event to ring buffer */ - event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] - : &dfs_pd->event_rb[0]; - event_buff->data[event_buff->t_rb] = *event; - event_buff->data[event_buff->t_rb].fetch_ts = jiffies; - - event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); - if (event_buff->t_rb == event_buff->h_rb) - event_buff->h_rb = mt76_incr(event_buff->h_rb, - MT_DFS_EVENT_BUFLEN); -} - -static int mt76x2_dfs_create_sequence(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event, - u16 cur_len) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sw_detector_params *sw_params; - u32 width_delta, with_sum, factor, cur_pri; - struct mt76x2_dfs_sequence seq, *seq_p; - struct mt76x2_dfs_event_rb *event_rb; - struct mt76x2_dfs_event *cur_event; - int i, j, end, pri; - - event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] - : &dfs_pd->event_rb[0]; - - i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN); - end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN); - - while (i != end) { - cur_event = &event_rb->data[i]; - with_sum = event->width + cur_event->width; - - sw_params = &dfs_pd->sw_dpd_params; - switch (dev->dfs_pd.region) { - case NL80211_DFS_FCC: - case NL80211_DFS_JP: - if (with_sum < 600) - width_delta = 8; - else - width_delta = with_sum >> 3; - break; - case NL80211_DFS_ETSI: - if (event->engine == 2) - width_delta = with_sum >> 6; - else if (with_sum < 620) - width_delta = 24; - else - width_delta = 8; - break; - case NL80211_DFS_UNSET: - default: - return -EINVAL; - } - - pri = event->ts - cur_event->ts; - if (abs(event->width - cur_event->width) > width_delta || - pri < sw_params->min_pri) - goto next; - - if (pri > sw_params->max_pri) - break; - - seq.pri = event->ts - cur_event->ts; - seq.first_ts = cur_event->ts; - seq.last_ts = event->ts; - seq.engine = event->engine; - seq.count = 2; - - j = mt76_decr(i, MT_DFS_EVENT_BUFLEN); - while (j != end) { - cur_event = &event_rb->data[j]; - cur_pri = event->ts - cur_event->ts; - factor = mt76x2_dfs_get_multiple(cur_pri, seq.pri, - sw_params->pri_margin); - if (factor > 0) { - seq.first_ts = cur_event->ts; - seq.count++; - } - - j = mt76_decr(j, MT_DFS_EVENT_BUFLEN); - } - if (seq.count <= cur_len) - goto next; - - seq_p = mt76x2_dfs_seq_pool_get(dev); - if (!seq_p) - return -ENOMEM; - - *seq_p = seq; - INIT_LIST_HEAD(&seq_p->head); - list_add(&seq_p->head, &dfs_pd->sequences); -next: - i = mt76_decr(i, MT_DFS_EVENT_BUFLEN); - } - return 0; -} - -static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sw_detector_params *sw_params; - struct mt76x2_dfs_sequence *seq, *tmp_seq; - u16 max_seq_len = 0; - u32 factor, pri; - - sw_params = &dfs_pd->sw_dpd_params; - list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { - if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) { - list_del_init(&seq->head); - mt76x2_dfs_seq_pool_put(dev, seq); - continue; - } - - if (event->engine != seq->engine) - continue; - - pri = event->ts - seq->last_ts; - factor = mt76x2_dfs_get_multiple(pri, seq->pri, - sw_params->pri_margin); - if (factor > 0) { - seq->last_ts = event->ts; - seq->count++; - max_seq_len = max_t(u16, max_seq_len, seq->count); - } - } - return max_seq_len; -} - -static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq; - - if (list_empty(&dfs_pd->sequences)) - return false; - - list_for_each_entry(seq, &dfs_pd->sequences, head) { - if (seq->count > MT_DFS_SEQUENCE_TH) { - dfs_pd->stats[seq->engine].sw_pattern++; - return true; - } - } - return false; -} - -static void mt76x2_dfs_add_events(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event event; - int i, seq_len; - - /* disable debug mode */ - mt76x2_dfs_set_capture_mode_ctrl(dev, false); - for (i = 0; i < MT_DFS_EVENT_LOOP; i++) { - if (!mt76x2_dfs_fetch_event(dev, &event)) - break; - - if (dfs_pd->last_event_ts > event.ts) - mt76x2_dfs_detector_reset(dev); - dfs_pd->last_event_ts = event.ts; - - if (!mt76x2_dfs_check_event(dev, &event)) - continue; - - seq_len = mt76x2_dfs_add_event_to_sequence(dev, &event); - mt76x2_dfs_create_sequence(dev, &event, seq_len); - - mt76x2_dfs_queue_event(dev, &event); - } - mt76x2_dfs_set_capture_mode_ctrl(dev, true); -} - -static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff; - struct mt76x2_dfs_event *event; - int i; - - for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { - event_buff = &dfs_pd->event_rb[i]; - - while (event_buff->h_rb != event_buff->t_rb) { - event = &event_buff->data[event_buff->h_rb]; - - /* sorted list */ - if (time_is_after_jiffies(event->fetch_ts + - MT_DFS_EVENT_WINDOW)) - break; - event_buff->h_rb = mt76_incr(event_buff->h_rb, - MT_DFS_EVENT_BUFLEN); - } - } -} - -static void mt76x2_dfs_tasklet(unsigned long arg) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *)arg; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - u32 engine_mask; - int i; - - if (test_bit(MT76_SCANNING, &dev->mt76.state)) - goto out; - - if (time_is_before_jiffies(dfs_pd->last_sw_check + - MT_DFS_SW_TIMEOUT)) { - bool radar_detected; - - dfs_pd->last_sw_check = jiffies; - - mt76x2_dfs_add_events(dev); - radar_detected = mt76x2_dfs_check_detection(dev); - if (radar_detected) { - /* sw detector rx radar pattern */ - ieee80211_radar_detected(dev->mt76.hw); - mt76x2_dfs_detector_reset(dev); - - return; - } - mt76x2_dfs_check_event_window(dev); - } - - engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); - if (!(engine_mask & 0xf)) - goto out; - - for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { - struct mt76x2_dfs_hw_pulse pulse; - - if (!(engine_mask & (1 << i))) - continue; - - pulse.engine = i; - mt76x2_dfs_get_hw_pulse(dev, &pulse); - - if (!mt76x2_dfs_check_hw_pulse(dev, &pulse)) { - dfs_pd->stats[i].hw_pulse_discarded++; - continue; - } - - /* hw detector rx radar pattern */ - dfs_pd->stats[i].hw_pattern++; - ieee80211_radar_detected(dev->mt76.hw); - mt76x2_dfs_detector_reset(dev); - - return; - } - - /* reset hw detector */ - mt76_wr(dev, MT_BBP(DFS, 1), 0xf); - -out: - mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); -} - -static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - switch (dev->dfs_pd.region) { - case NL80211_DFS_FCC: - dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI; - dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI; - dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; - break; - case NL80211_DFS_ETSI: - dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI; - dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI; - dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2; - break; - case NL80211_DFS_JP: - dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI; - dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI; - dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; - break; - case NL80211_DFS_UNSET: - default: - break; - } -} - -static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) -{ - u32 data; - u8 i, shift; - const struct mt76x2_radar_specs *radar_specs; - - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_40: - shift = MT_DFS_NUM_ENGINES; - break; - case NL80211_CHAN_WIDTH_80: - shift = 2 * MT_DFS_NUM_ENGINES; - break; - default: - shift = 0; - break; - } - - switch (dev->dfs_pd.region) { - case NL80211_DFS_FCC: - radar_specs = &fcc_radar_specs[shift]; - break; - case NL80211_DFS_ETSI: - radar_specs = &etsi_radar_specs[shift]; - break; - case NL80211_DFS_JP: - if (dev->mt76.chandef.chan->center_freq >= 5250 && - dev->mt76.chandef.chan->center_freq <= 5350) - radar_specs = &jp_w53_radar_specs[shift]; - else - radar_specs = &jp_w56_radar_specs[shift]; - break; - case NL80211_DFS_UNSET: - default: - return; - } - - data = (MT_DFS_VGA_MASK << 16) | - (MT_DFS_PWR_GAIN_OFFSET << 12) | - (MT_DFS_PWR_DOWN_TIME << 8) | - (MT_DFS_SYM_ROUND << 4) | - (MT_DFS_DELTA_DELAY & 0xf); - mt76_wr(dev, MT_BBP(DFS, 2), data); - - data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK; - mt76_wr(dev, MT_BBP(DFS, 3), data); - - for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { - /* configure engine */ - mt76_wr(dev, MT_BBP(DFS, 0), i); - - /* detection mode + avg_len */ - data = ((radar_specs[i].avg_len & 0x1ff) << 16) | - (radar_specs[i].mode & 0xf); - mt76_wr(dev, MT_BBP(DFS, 4), data); - - /* dfs energy */ - data = ((radar_specs[i].e_high & 0x0fff) << 16) | - (radar_specs[i].e_low & 0x0fff); - mt76_wr(dev, MT_BBP(DFS, 5), data); - - /* dfs period */ - mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low); - mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high); - - /* dfs burst */ - mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low); - mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high); - - /* dfs width */ - data = ((radar_specs[i].w_high & 0x0fff) << 16) | - (radar_specs[i].w_low & 0x0fff); - mt76_wr(dev, MT_BBP(DFS, 14), data); - - /* dfs margins */ - data = (radar_specs[i].w_margin << 16) | - radar_specs[i].t_margin; - mt76_wr(dev, MT_BBP(DFS, 15), data); - - /* dfs event expiration */ - mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration); - - /* dfs pwr adj */ - mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp); - } - - /* reset status */ - mt76_wr(dev, MT_BBP(DFS, 1), 0xf); - mt76_wr(dev, MT_BBP(DFS, 36), 0x3); - - /* enable detection*/ - mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); - mt76_wr(dev, 0x212c, 0x0c350001); -} - -void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev) -{ - u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31; - - agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8)); - agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4)); - - val_r8 = (agc_r8 & 0x00007e00) >> 9; - val_r4 = agc_r4 & ~0x1f000000; - val_r4 += (((val_r8 + 1) >> 1) << 24); - mt76_wr(dev, MT_BBP(AGC, 4), val_r4); - - dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4); - dfs_r31 += val_r8; - dfs_r31 -= (agc_r8 & 0x00000038) >> 3; - dfs_r31 = (dfs_r31 << 16) | 0x00000307; - mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31); - - mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071); -} - -void mt76x2_dfs_init_params(struct mt76x2_dev *dev) -{ - struct cfg80211_chan_def *chandef = &dev->mt76.chandef; - - if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && - dev->dfs_pd.region != NL80211_DFS_UNSET) { - mt76x2_dfs_init_sw_detector(dev); - mt76x2_dfs_set_bbp_params(dev); - /* enable debug mode */ - mt76x2_dfs_set_capture_mode_ctrl(dev, true); - - mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); - mt76_rmw_field(dev, MT_INT_TIMER_EN, - MT_INT_TIMER_EN_GP_TIMER_EN, 1); - } else { - /* disable hw detector */ - mt76_wr(dev, MT_BBP(DFS, 0), 0); - /* clear detector status */ - mt76_wr(dev, MT_BBP(DFS, 1), 0xf); - mt76_wr(dev, 0x212c, 0); - - mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); - mt76_rmw_field(dev, MT_INT_TIMER_EN, - MT_INT_TIMER_EN_GP_TIMER_EN, 0); - } -} - -void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - INIT_LIST_HEAD(&dfs_pd->sequences); - INIT_LIST_HEAD(&dfs_pd->seq_pool); - dfs_pd->region = NL80211_DFS_UNSET; - dfs_pd->last_sw_check = jiffies; - tasklet_init(&dfs_pd->dfs_tasklet, mt76x2_dfs_tasklet, - (unsigned long)dev); -} - -void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, - enum nl80211_dfs_regions region) -{ - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - - if (dfs_pd->region != region) { - tasklet_disable(&dfs_pd->dfs_tasklet); - dfs_pd->region = region; - mt76x2_dfs_init_params(dev); - tasklet_enable(&dfs_pd->dfs_tasklet); - } -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h deleted file mode 100644 index 693f421bf096..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2016 Lorenzo Bianconi - * - * 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 __MT76x2_DFS_H -#define __MT76x2_DFS_H - -#include -#include - -#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ -#define MT_DFS_NUM_ENGINES 4 - -/* bbp params */ -#define MT_DFS_SYM_ROUND 0 -#define MT_DFS_DELTA_DELAY 2 -#define MT_DFS_VGA_MASK 0 -#define MT_DFS_PWR_GAIN_OFFSET 3 -#define MT_DFS_PWR_DOWN_TIME 0xf -#define MT_DFS_RX_PE_MASK 0xff -#define MT_DFS_PKT_END_MASK 0 -#define MT_DFS_CH_EN 0xf - -/* sw detector params */ -#define MT_DFS_EVENT_LOOP 64 -#define MT_DFS_SW_TIMEOUT (HZ / 20) -#define MT_DFS_EVENT_WINDOW (HZ / 5) -#define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) -#define MT_DFS_EVENT_TIME_MARGIN 2000 -#define MT_DFS_PRI_MARGIN 4 -#define MT_DFS_SEQUENCE_TH 6 - -#define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) -#define MT_DFS_FCC_MIN_PRI (3000 - 2) -#define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) -#define MT_DFS_JP_MIN_PRI (28500 - 2) -#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) -#define MT_DFS_ETSI_MIN_PRI (4500 - 20) - -struct mt76x2_radar_specs { - u8 mode; - u16 avg_len; - u16 e_low; - u16 e_high; - u16 w_low; - u16 w_high; - u16 w_margin; - u32 t_low; - u32 t_high; - u16 t_margin; - u32 b_low; - u32 b_high; - u32 event_expiration; - u16 pwr_jmp; -}; - -#define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) -#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) -#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) -#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) -struct mt76x2_dfs_event { - unsigned long fetch_ts; - u32 ts; - u16 width; - u8 engine; -}; - -#define MT_DFS_EVENT_BUFLEN 256 -struct mt76x2_dfs_event_rb { - struct mt76x2_dfs_event data[MT_DFS_EVENT_BUFLEN]; - int h_rb, t_rb; -}; - -struct mt76x2_dfs_sequence { - struct list_head head; - u32 first_ts; - u32 last_ts; - u32 pri; - u16 count; - u8 engine; -}; - -struct mt76x2_dfs_hw_pulse { - u8 engine; - u32 period; - u32 w1; - u32 w2; - u32 burst; -}; - -struct mt76x2_dfs_sw_detector_params { - u32 min_pri; - u32 max_pri; - u32 pri_margin; -}; - -struct mt76x2_dfs_engine_stats { - u32 hw_pattern; - u32 hw_pulse_discarded; - u32 sw_pattern; -}; - -struct mt76x2_dfs_seq_stats { - u32 seq_pool_len; - u32 seq_len; -}; - -struct mt76x2_dfs_pattern_detector { - enum nl80211_dfs_regions region; - - u8 chirp_pulse_cnt; - u32 chirp_pulse_ts; - - struct mt76x2_dfs_sw_detector_params sw_dpd_params; - struct mt76x2_dfs_event_rb event_rb[2]; - - struct list_head sequences; - struct list_head seq_pool; - struct mt76x2_dfs_seq_stats seq_stats; - - unsigned long last_sw_check; - u32 last_event_ts; - - struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; - struct tasklet_struct dfs_tasklet; -}; - -void mt76x2_dfs_init_params(struct mt76x2_dev *dev); -void mt76x2_dfs_init_detector(struct mt76x2_dev *dev); -void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev); -void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, - enum nl80211_dfs_regions region); - -#endif /* __MT76x2_DFS_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c deleted file mode 100644 index 7e5eccda47f8..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 "mt76x2.h" -#include "mt76x02_dma.h" -#include "mt76x02_util.h" - -void mt76x2_tx_tasklet(unsigned long data) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *) data; - int i; - - mt76x2_mac_process_tx_status_fifo(dev); - - for (i = MT_TXQ_MCU; i >= 0; i--) - mt76_queue_tx_cleanup(dev, i, false); - - mt76x2_mac_poll_tx_status(dev, false); - mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); -} - -void mt76x2_dma_cleanup(struct mt76x2_dev *dev) -{ - tasklet_kill(&dev->tx_tasklet); - mt76_dma_cleanup(&dev->mt76); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c deleted file mode 100644 index 136faa4066a5..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include -#include "mt76x2.h" -#include "mt76x2_eeprom.h" - -#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 - -static int -mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, - void *dest, int len) -{ - if (field + len > dev->mt76.eeprom.size) - return -1; - - memcpy(dest, dev->mt76.eeprom.data + field, len); - return 0; -} - -static int -mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) -{ - void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; - - memcpy(dev->mt76.macaddr, src, ETH_ALEN); - return 0; -} - -static bool -mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) -{ - u16 *efuse_w = (u16 *) efuse; - - if (efuse_w[MT_EE_NIC_CONF_0] != 0) - return false; - - if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) - return false; - - if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) - return false; - - if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) - return false; - - if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) - return false; - - if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) - return false; - - return true; -} - -static void -mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) -{ -#define GROUP_5G(_id) \ - MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ - MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ - MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ - MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 - - static const u8 cal_free_bytes[] = { - MT_EE_XTAL_TRIM_1, - MT_EE_TX_POWER_EXT_PA_5G + 1, - MT_EE_TX_POWER_0_START_2G, - MT_EE_TX_POWER_0_START_2G + 1, - MT_EE_TX_POWER_1_START_2G, - MT_EE_TX_POWER_1_START_2G + 1, - GROUP_5G(0), - GROUP_5G(1), - GROUP_5G(2), - GROUP_5G(3), - GROUP_5G(4), - GROUP_5G(5), - MT_EE_RF_2G_TSSI_OFF_TXPOWER, - MT_EE_RF_2G_RX_HIGH_GAIN + 1, - MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, - MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, - MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, - MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, - MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, - MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, - }; - u8 *eeprom = dev->mt76.eeprom.data; - u8 prev_grp0[4] = { - eeprom[MT_EE_TX_POWER_0_START_5G], - eeprom[MT_EE_TX_POWER_0_START_5G + 1], - eeprom[MT_EE_TX_POWER_1_START_5G], - eeprom[MT_EE_TX_POWER_1_START_5G + 1] - }; - u16 val; - int i; - - if (!mt76x2_has_cal_free_data(dev, efuse)) - return; - - for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { - int offset = cal_free_bytes[i]; - - eeprom[offset] = efuse[offset]; - } - - if (!(efuse[MT_EE_TX_POWER_0_START_5G] | - efuse[MT_EE_TX_POWER_0_START_5G + 1])) - memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); - if (!(efuse[MT_EE_TX_POWER_1_START_5G] | - efuse[MT_EE_TX_POWER_1_START_5G + 1])) - memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); - - val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); - if (val != 0xffff) - eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; - - val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); - if (val != 0xffff) - eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; - - val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); - if (val != 0xffff) - eeprom[MT_EE_BT_PMUCFG] = val & 0xff; -} - -static int mt76x2_check_eeprom(struct mt76x2_dev *dev) -{ - u16 val = get_unaligned_le16(dev->mt76.eeprom.data); - - if (!val) - val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); - - switch (val) { - case 0x7662: - case 0x7612: - return 0; - default: - dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); - return -EINVAL; - } -} - -static int -mt76x2_eeprom_load(struct mt76x2_dev *dev) -{ - void *efuse; - bool found; - int ret; - - ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); - if (ret < 0) - return ret; - - found = ret; - if (found) - found = !mt76x2_check_eeprom(dev); - - dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, - GFP_KERNEL); - dev->mt76.otp.size = MT7662_EEPROM_SIZE; - if (!dev->mt76.otp.data) - return -ENOMEM; - - efuse = dev->mt76.otp.data; - - if (mt76x02_get_efuse_data(&dev->mt76, 0, efuse, - MT7662_EEPROM_SIZE, MT_EE_READ)) - goto out; - - if (found) { - mt76x2_apply_cal_free_data(dev, efuse); - } else { - /* FIXME: check if efuse data is complete */ - found = true; - memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); - } - -out: - if (!found) - return -ENOENT; - - return 0; -} - -static void -mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) -{ - s8 *dest = dev->cal.rx.high_gain; - - if (!mt76x02_field_valid(val)) { - dest[0] = 0; - dest[1] = 0; - return; - } - - dest[0] = mt76x02_sign_extend(val, 4); - dest[1] = mt76x02_sign_extend(val >> 4, 4); -} - -static void -mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) -{ - s8 *dest = dev->cal.rx.rssi_offset; - - if (!mt76x02_field_valid(val)) { - dest[chain] = 0; - return; - } - - dest[chain] = mt76x02_sign_extend_optional(val, 7); -} - -static enum mt76x2_cal_channel_group -mt76x2_get_cal_channel_group(int channel) -{ - if (channel >= 184 && channel <= 196) - return MT_CH_5G_JAPAN; - if (channel <= 48) - return MT_CH_5G_UNII_1; - if (channel <= 64) - return MT_CH_5G_UNII_2; - if (channel <= 114) - return MT_CH_5G_UNII_2E_1; - if (channel <= 144) - return MT_CH_5G_UNII_2E_2; - return MT_CH_5G_UNII_3; -} - -static u8 -mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) -{ - enum mt76x2_cal_channel_group group; - - group = mt76x2_get_cal_channel_group(channel); - switch (group) { - case MT_CH_5G_JAPAN: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); - case MT_CH_5G_UNII_1: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; - case MT_CH_5G_UNII_2: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); - case MT_CH_5G_UNII_2E_1: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; - case MT_CH_5G_UNII_2E_2: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); - default: - return mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; - } -} - -void mt76x2_read_rx_gain(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - int channel = chan->hw_value; - s8 lna_5g[3], lna_2g; - u8 lna; - u16 val; - - if (chan->band == NL80211_BAND_2GHZ) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; - else - val = mt76x2_get_5g_rx_gain(dev, channel); - - mt76x2_set_rx_gain_group(dev, val); - - mt76x02_get_rx_gain(&dev->mt76, chan->band, &val, &lna_2g, lna_5g); - mt76x2_set_rssi_offset(dev, 0, val); - mt76x2_set_rssi_offset(dev, 1, val >> 8); - - dev->cal.rx.mcu_gain = (lna_2g & 0xff); - dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; - dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; - dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; - - lna = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan); - dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); -} -EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); - -void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, - struct ieee80211_channel *chan) -{ - bool is_5ghz; - u16 val; - - is_5ghz = chan->band == NL80211_BAND_5GHZ; - - memset(t, 0, sizeof(*t)); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK); - t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); - t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); - - if (is_5ghz) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_5G_6M); - else - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_2G_6M); - t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); - t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); - - if (is_5ghz) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_5G_24M); - else - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_2G_24M); - t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); - t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0); - t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); - t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4); - t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); - t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8); - t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); - t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12); - t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); - t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0); - t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val); - t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4); - t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val); - t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8); - if (!is_5ghz) - val >>= 8; - t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8); - - memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8); - t->stbc[8] = t->vht[8]; - t->stbc[9] = t->vht[9]; -} -EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); - -static void -mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan, int chain, int offset) -{ - int channel = chan->hw_value; - int delta_idx; - u8 data[6]; - u16 val; - - if (channel < 6) - delta_idx = 3; - else if (channel < 11) - delta_idx = 4; - else - delta_idx = 5; - - mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); - - t->chain[chain].tssi_slope = data[0]; - t->chain[chain].tssi_offset = data[1]; - t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER); - t->target_power = val >> 8; -} - -static void -mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan, int chain, int offset) -{ - int channel = chan->hw_value; - enum mt76x2_cal_channel_group group; - int delta_idx; - u16 val; - u8 data[5]; - - group = mt76x2_get_cal_channel_group(channel); - offset += group * MT_TX_POWER_GROUP_SIZE_5G; - - if (channel >= 192) - delta_idx = 4; - else if (channel >= 184) - delta_idx = 3; - else if (channel < 44) - delta_idx = 3; - else if (channel < 52) - delta_idx = 4; - else if (channel < 58) - delta_idx = 3; - else if (channel < 98) - delta_idx = 4; - else if (channel < 106) - delta_idx = 3; - else if (channel < 116) - delta_idx = 4; - else if (channel < 130) - delta_idx = 3; - else if (channel < 149) - delta_idx = 4; - else if (channel < 157) - delta_idx = 3; - else - delta_idx = 4; - - mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); - - t->chain[chain].tssi_slope = data[0]; - t->chain[chain].tssi_offset = data[1]; - t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN); - t->target_power = val & 0xff; -} - -void mt76x2_get_power_info(struct mt76x2_dev *dev, - struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan) -{ - u16 bw40, bw80; - - memset(t, 0, sizeof(*t)); - - bw40 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW40); - bw80 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW80); - - if (chan->band == NL80211_BAND_5GHZ) { - bw40 >>= 8; - mt76x2_get_power_info_5g(dev, t, chan, 0, - MT_EE_TX_POWER_0_START_5G); - mt76x2_get_power_info_5g(dev, t, chan, 1, - MT_EE_TX_POWER_1_START_5G); - } else { - mt76x2_get_power_info_2g(dev, t, chan, 0, - MT_EE_TX_POWER_0_START_2G); - mt76x2_get_power_info_2g(dev, t, chan, 1, - MT_EE_TX_POWER_1_START_2G); - } - - if (mt76x02_tssi_enabled(&dev->mt76) || - !mt76x02_field_valid(t->target_power)) - t->target_power = t->chain[0].target_power; - - t->delta_bw40 = mt76x02_rate_power_val(bw40); - t->delta_bw80 = mt76x02_rate_power_val(bw80); -} -EXPORT_SYMBOL_GPL(mt76x2_get_power_info); - -int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) -{ - enum nl80211_band band = dev->mt76.chandef.chan->band; - u16 val, slope; - u8 bounds; - - memset(t, 0, sizeof(*t)); - - if (!mt76x02_temp_tx_alc_enabled(&dev->mt76)) - return -EINVAL; - - if (!mt76x02_ext_pa_enabled(&dev->mt76, band)) - return -EINVAL; - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8; - t->temp_25_ref = val & 0x7f; - if (band == NL80211_BAND_5GHZ) { - slope = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_TEMP_COMP_SLOPE_5G); - bounds = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_EXT_PA_5G); - } else { - slope = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_TEMP_COMP_SLOPE_2G); - bounds = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_DELTA_BW80) >> 8; - } - - t->high_slope = slope & 0xff; - t->low_slope = slope >> 8; - t->lower_bound = 0 - (bounds & 0xf); - t->upper_bound = (bounds >> 4) & 0xf; - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); - -int mt76x2_eeprom_init(struct mt76x2_dev *dev) -{ - int ret; - - ret = mt76x2_eeprom_load(dev); - if (ret) - return ret; - - mt76x02_eeprom_parse_hw_cap(&dev->mt76); - mt76x2_eeprom_get_macaddr(dev); - mt76_eeprom_override(&dev->mt76); - dev->mt76.macaddr[0] &= ~BIT(1); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_eeprom_init); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h deleted file mode 100644 index c2e99bbeac3b..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 __MT76x2_EEPROM_H -#define __MT76x2_EEPROM_H - -#include "mt76x02_eeprom.h" - -enum mt76x2_cal_channel_group { - MT_CH_5G_JAPAN, - MT_CH_5G_UNII_1, - MT_CH_5G_UNII_2, - MT_CH_5G_UNII_2E_1, - MT_CH_5G_UNII_2E_2, - MT_CH_5G_UNII_3, - __MT_CH_MAX -}; - -struct mt76x2_tx_power_info { - u8 target_power; - - s8 delta_bw40; - s8 delta_bw80; - - struct { - s8 tssi_slope; - s8 tssi_offset; - s8 target_power; - s8 delta; - } chain[MT_MAX_CHAINS]; -}; - -struct mt76x2_temp_comp { - u8 temp_25_ref; - int lower_bound; /* J */ - int upper_bound; /* J */ - unsigned int high_slope; /* J / dB */ - unsigned int low_slope; /* J / dB */ -}; - -void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, - struct ieee80211_channel *chan); -void mt76x2_get_power_info(struct mt76x2_dev *dev, - struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan); -int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); -void mt76x2_read_rx_gain(struct mt76x2_dev *dev); - -static inline bool -mt76x2_has_ext_lna(struct mt76x2_dev *dev) -{ - u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); - - if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) - return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; - else - return val & MT_EE_NIC_CONF_1_LNA_EXT_5G; -} - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c deleted file mode 100644 index 3f77c13a6d54..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_mcu.h" -#include "mt76x02_util.h" -#include "mt76x02_dma.h" - -static void -mt76x2_mac_pbf_init(struct mt76x2_dev *dev) -{ - u32 val; - - val = MT_PBF_SYS_CTRL_MCU_RESET | - MT_PBF_SYS_CTRL_DMA_RESET | - MT_PBF_SYS_CTRL_MAC_RESET | - MT_PBF_SYS_CTRL_PBF_RESET | - MT_PBF_SYS_CTRL_ASY_RESET; - - mt76_set(dev, MT_PBF_SYS_CTRL, val); - mt76_clear(dev, MT_PBF_SYS_CTRL, val); - - mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); - mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); -} - -static void -mt76x2_fixup_xtal(struct mt76x2_dev *dev) -{ - u16 eep_val; - s8 offset = 0; - - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); - - offset = eep_val & 0x7f; - if ((eep_val & 0xff) == 0xff) - offset = 0; - else if (eep_val & 0x80) - offset = 0 - offset; - - eep_val >>= 8; - if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); - eep_val &= 0xff; - - if (eep_val == 0x00 || eep_val == 0xff) - eep_val = 0x14; - } - - eep_val &= 0x7f; - mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); - mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); - - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); - switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { - case 0: - mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); - break; - case 1: - mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); - break; - default: - break; - } -} - -static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) -{ - static const u8 null_addr[ETH_ALEN] = {}; - const u8 *macaddr = dev->mt76.macaddr; - u32 val; - int i, k; - - if (!mt76x02_wait_for_mac(&dev->mt76)) - return -ETIMEDOUT; - - val = mt76_rr(dev, MT_WPDMA_GLO_CFG); - - val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | - MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_EN | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY | - MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); - val |= FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); - - mt76_wr(dev, MT_WPDMA_GLO_CFG, val); - - mt76x2_mac_pbf_init(dev); - mt76_write_mac_initvals(dev); - mt76x2_fixup_xtal(dev); - - mt76_clear(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_RESET_CSR | - MT_MAC_SYS_CTRL_RESET_BBP); - - if (is_mt7612(dev)) - mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); - - mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); - mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); - - mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); - mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); - usleep_range(5000, 10000); - mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); - - mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); - mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); - - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(macaddr)); - mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(macaddr + 4)); - - mt76_wr(dev, MT_MAC_BSSID_DW0, get_unaligned_le32(macaddr)); - mt76_wr(dev, MT_MAC_BSSID_DW1, get_unaligned_le16(macaddr + 4) | - FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ - MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); - - /* Fire a pre-TBTT interrupt 8 ms before TBTT */ - mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, - 8 << 4); - mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, - MT_DFS_GP_INTERVAL); - mt76_wr(dev, MT_INT_TIMER_EN, 0); - - mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); - if (!hard) - return 0; - - for (i = 0; i < 256 / 32; i++) - mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); - - for (i = 0; i < 256; i++) - mt76x02_mac_wcid_setup(&dev->mt76, i, 0, NULL); - - for (i = 0; i < MT_MAX_VIFS; i++) - mt76x02_mac_wcid_setup(&dev->mt76, MT_VIF_WCID(i), i, NULL); - - for (i = 0; i < 16; i++) - for (k = 0; k < 4; k++) - mt76x02_mac_shared_key_setup(&dev->mt76, i, k, NULL); - - for (i = 0; i < 8; i++) { - mt76x2_mac_set_bssid(dev, i, null_addr); - mt76x2_mac_set_beacon(dev, i, NULL); - } - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_STAT_FIFO); - - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY | - FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - - mt76x02_set_beacon_offsets(&dev->mt76); - - mt76x2_set_tx_ackto(dev); - - return 0; -} - -int mt76x2_mac_start(struct mt76x2_dev *dev) -{ - int i; - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_AGG_CNT(i)); - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_STAT_FIFO); - - memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); - mt76x02_mac_start(&dev->mt76); - - return 0; -} - -void mt76x2_mac_resume(struct mt76x2_dev *dev) -{ - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); -} - -static void -mt76x2_power_on_rf_patch(struct mt76x2_dev *dev) -{ - mt76_set(dev, 0x10130, BIT(0) | BIT(16)); - udelay(1); - - mt76_clear(dev, 0x1001c, 0xff); - mt76_set(dev, 0x1001c, 0x30); - - mt76_wr(dev, 0x10014, 0x484f); - udelay(1); - - mt76_set(dev, 0x10130, BIT(17)); - udelay(125); - - mt76_clear(dev, 0x10130, BIT(16)); - udelay(50); - - mt76_set(dev, 0x1014c, BIT(19) | BIT(20)); -} - -static void -mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit) -{ - int shift = unit ? 8 : 0; - - /* Enable RF BG */ - mt76_set(dev, 0x10130, BIT(0) << shift); - udelay(10); - - /* Enable RFDIG LDO/AFE/ABB/ADDA */ - mt76_set(dev, 0x10130, (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift); - udelay(10); - - /* Switch RFDIG power to internal LDO */ - mt76_clear(dev, 0x10130, BIT(2) << shift); - udelay(10); - - mt76x2_power_on_rf_patch(dev); - - mt76_set(dev, 0x530, 0xf); -} - -static void -mt76x2_power_on(struct mt76x2_dev *dev) -{ - u32 val; - - /* Turn on WL MTCMOS */ - mt76_set(dev, MT_WLAN_MTC_CTRL, MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); - - val = MT_WLAN_MTC_CTRL_STATE_UP | - MT_WLAN_MTC_CTRL_PWR_ACK | - MT_WLAN_MTC_CTRL_PWR_ACK_S; - - mt76_poll(dev, MT_WLAN_MTC_CTRL, val, val, 1000); - - mt76_clear(dev, MT_WLAN_MTC_CTRL, 0x7f << 16); - udelay(10); - - mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xf << 24); - udelay(10); - - mt76_set(dev, MT_WLAN_MTC_CTRL, 0xf << 24); - mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xfff); - - /* Turn on AD/DA power down */ - mt76_clear(dev, 0x11204, BIT(3)); - - /* WLAN function enable */ - mt76_set(dev, 0x10080, BIT(0)); - - /* Release BBP software reset */ - mt76_clear(dev, 0x10064, BIT(18)); - - mt76x2_power_on_rf(dev, 0); - mt76x2_power_on_rf(dev, 1); -} - -void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) -{ - u8 ackto, sifs, slottime = dev->slottime; - - /* As defined by IEEE 802.11-2007 17.3.8.6 */ - slottime += 3 * dev->coverage_class; - mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, - MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); - - sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, - MT_XIFS_TIME_CFG_OFDM_SIFS); - - ackto = slottime + sifs; - mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, - MT_TX_TIMEOUT_CFG_ACKTO, ackto); -} - -int mt76x2_init_hardware(struct mt76x2_dev *dev) -{ - int ret; - - tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, - (unsigned long) dev); - - mt76x02_dma_disable(&dev->mt76); - mt76x2_reset_wlan(dev, true); - mt76x2_power_on(dev); - - ret = mt76x2_eeprom_init(dev); - if (ret) - return ret; - - ret = mt76x2_mac_reset(dev, true); - if (ret) - return ret; - - dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); - - ret = mt76x02_dma_init(&dev->mt76); - if (ret) - return ret; - - set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - ret = mt76x2_mac_start(dev); - if (ret) - return ret; - - ret = mt76x2_mcu_init(dev); - if (ret) - return ret; - - mt76x2_mac_stop(dev, false); - - return 0; -} - -void mt76x2_stop_hardware(struct mt76x2_dev *dev) -{ - cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mac_work); - mt76x02_mcu_set_radio_state(&dev->mt76, false, true); - mt76x2_mac_stop(dev, false); -} - -void mt76x2_cleanup(struct mt76x2_dev *dev) -{ - tasklet_disable(&dev->dfs_pd.dfs_tasklet); - tasklet_disable(&dev->pre_tbtt_tasklet); - mt76x2_stop_hardware(dev); - mt76x2_dma_cleanup(dev); - mt76x02_mcu_cleanup(&dev->mt76); -} - -struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) -{ - static const struct mt76_driver_ops drv_ops = { - .txwi_size = sizeof(struct mt76x02_txwi), - .update_survey = mt76x2_update_channel, - .tx_prepare_skb = mt76x2_tx_prepare_skb, - .tx_complete_skb = mt76x2_tx_complete_skb, - .rx_skb = mt76x2_queue_rx_skb, - .rx_poll_complete = mt76x2_rx_poll_complete, - .sta_ps = mt76x2_sta_ps, - .get_max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj, - }; - struct mt76x2_dev *dev; - struct mt76_dev *mdev; - - mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops); - if (!mdev) - return NULL; - - dev = container_of(mdev, struct mt76x2_dev, mt76); - mdev->dev = pdev; - mdev->drv = &drv_ops; - - return dev; -} - -static void mt76x2_regd_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct mt76x2_dev *dev = hw->priv; - - mt76x2_dfs_set_domain(dev, request->dfs_region); -} - -static const struct ieee80211_iface_limit if_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_ADHOC) - }, { - .max = 8, - .types = BIT(NL80211_IFTYPE_STATION) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP) - }, -}; - -static const struct ieee80211_iface_combination if_comb[] = { - { - .limits = if_limits, - .n_limits = ARRAY_SIZE(if_limits), - .max_interfaces = 8, - .num_different_channels = 1, - .beacon_int_infra_match = true, - .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80), - } -}; - -static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on, - u8 delay_off) -{ - struct mt76x2_dev *dev = container_of(mt76, struct mt76x2_dev, - mt76); - u32 val; - - val = MT_LED_STATUS_DURATION(0xff) | - MT_LED_STATUS_OFF(delay_off) | - MT_LED_STATUS_ON(delay_on); - - mt76_wr(dev, MT_LED_S0(mt76->led_pin), val); - mt76_wr(dev, MT_LED_S1(mt76->led_pin), val); - - val = MT_LED_CTRL_REPLAY(mt76->led_pin) | - MT_LED_CTRL_KICK(mt76->led_pin); - if (mt76->led_al) - val |= MT_LED_CTRL_POLARITY(mt76->led_pin); - mt76_wr(dev, MT_LED_CTRL, val); -} - -static int mt76x2_led_set_blink(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); - u8 delta_on, delta_off; - - delta_off = max_t(u8, *delay_off / 10, 1); - delta_on = max_t(u8, *delay_on / 10, 1); - - mt76x2_led_set_config(mt76, delta_on, delta_off); - return 0; -} - -static void mt76x2_led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, - led_cdev); - - if (!brightness) - mt76x2_led_set_config(mt76, 0, 0xff); - else - mt76x2_led_set_config(mt76, 0xff, 0); -} - -int mt76x2_register_device(struct mt76x2_dev *dev) -{ - struct ieee80211_hw *hw = mt76_hw(dev); - struct wiphy *wiphy = hw->wiphy; - void *status_fifo; - int fifo_size; - int i, ret; - - fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); - status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); - if (!status_fifo) - return -ENOMEM; - - tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long)dev); - kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); - INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); - INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); - - mt76x2_init_device(dev); - - ret = mt76x2_init_hardware(dev); - if (ret) - return ret; - - for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { - u8 *addr = dev->macaddr_list[i].addr; - - memcpy(addr, dev->mt76.macaddr, ETH_ALEN); - - if (!i) - continue; - - addr[0] |= BIT(1); - addr[0] ^= ((i - 1) << 2); - } - wiphy->addresses = dev->macaddr_list; - wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); - - wiphy->iface_combinations = if_comb; - wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - - wiphy->reg_notifier = mt76x2_regd_notifier; - - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - - wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); - - mt76x2_dfs_init_detector(dev); - - /* init led callbacks */ - dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; - - ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, - ARRAY_SIZE(mt76x02_rates)); - if (ret) - goto fail; - - mt76x2_init_debugfs(dev); - mt76x2_init_txpower(dev, &dev->mt76.sband_2g.sband); - mt76x2_init_txpower(dev, &dev->mt76.sband_5g.sband); - - return 0; - -fail: - mt76x2_stop_hardware(dev); - return ret; -} - - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c deleted file mode 100644 index f4c4cde9301e..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_phy.h" - -static void -mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) -{ - u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL); - - if (enable) - val |= (MT_WLAN_FUN_CTRL_WLAN_EN | - MT_WLAN_FUN_CTRL_WLAN_CLK_EN); - else - val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN | - MT_WLAN_FUN_CTRL_WLAN_CLK_EN); - - mt76_wr(dev, MT_WLAN_FUN_CTRL, val); - udelay(20); -} - -void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) -{ - u32 val; - - if (!enable) - goto out; - - val = mt76_rr(dev, MT_WLAN_FUN_CTRL); - - val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; - - if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { - val |= MT_WLAN_FUN_CTRL_WLAN_RESET_RF; - mt76_wr(dev, MT_WLAN_FUN_CTRL, val); - udelay(20); - - val &= ~MT_WLAN_FUN_CTRL_WLAN_RESET_RF; - } - - mt76_wr(dev, MT_WLAN_FUN_CTRL, val); - udelay(20); - -out: - mt76x2_set_wlan_state(dev, enable); -} -EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); - -void mt76_write_mac_initvals(struct mt76x2_dev *dev) -{ -#define DEFAULT_PROT_CFG_CCK \ - (FIELD_PREP(MT_PROT_CFG_RATE, 0x3) | \ - FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ - FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ - MT_PROT_CFG_RTS_THRESH) - -#define DEFAULT_PROT_CFG_OFDM \ - (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ - FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ - FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ - MT_PROT_CFG_RTS_THRESH) - -#define DEFAULT_PROT_CFG_20 \ - (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ - FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ - FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ - FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x17)) - -#define DEFAULT_PROT_CFG_40 \ - (FIELD_PREP(MT_PROT_CFG_RATE, 0x2084) | \ - FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ - FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ - FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f)) - - static const struct mt76_reg_pair vals[] = { - /* Copied from MediaTek reference source */ - { MT_PBF_SYS_CTRL, 0x00080c00 }, - { MT_PBF_CFG, 0x1efebcff }, - { MT_FCE_PSE_CTRL, 0x00000001 }, - { MT_MAC_SYS_CTRL, 0x0000000c }, - { MT_MAX_LEN_CFG, 0x003e3f00 }, - { MT_AMPDU_MAX_LEN_20M1S, 0xaaa99887 }, - { MT_AMPDU_MAX_LEN_20M2S, 0x000000aa }, - { MT_XIFS_TIME_CFG, 0x33a40d0a }, - { MT_BKOFF_SLOT_CFG, 0x00000209 }, - { MT_TBTT_SYNC_CFG, 0x00422010 }, - { MT_PWR_PIN_CFG, 0x00000000 }, - { 0x1238, 0x001700c8 }, - { MT_TX_SW_CFG0, 0x00101001 }, - { MT_TX_SW_CFG1, 0x00010000 }, - { MT_TX_SW_CFG2, 0x00000000 }, - { MT_TXOP_CTRL_CFG, 0x0400583f }, - { MT_TX_RTS_CFG, 0x00100020 }, - { MT_TX_TIMEOUT_CFG, 0x000a2290 }, - { MT_TX_RETRY_CFG, 0x47f01f0f }, - { MT_EXP_ACK_TIME, 0x002c00dc }, - { MT_TX_PROT_CFG6, 0xe3f42004 }, - { MT_TX_PROT_CFG7, 0xe3f42084 }, - { MT_TX_PROT_CFG8, 0xe3f42104 }, - { MT_PIFS_TX_CFG, 0x00060fff }, - { MT_RX_FILTR_CFG, 0x00015f97 }, - { MT_LEGACY_BASIC_RATE, 0x0000017f }, - { MT_HT_BASIC_RATE, 0x00004003 }, - { MT_PN_PAD_MODE, 0x00000003 }, - { MT_TXOP_HLDR_ET, 0x00000002 }, - { 0xa44, 0x00000000 }, - { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, - { MT_TSO_CTRL, 0x00000000 }, - { MT_AUX_CLK_CFG, 0x00000000 }, - { MT_DACCLK_EN_DLY_CFG, 0x00000000 }, - { MT_TX_ALC_CFG_4, 0x00000000 }, - { MT_TX_ALC_VGA3, 0x00000000 }, - { MT_TX_PWR_CFG_0, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_1, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_2, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_3, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_4, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_7, 0x3a3a3a3a }, - { MT_TX_PWR_CFG_8, 0x0000003a }, - { MT_TX_PWR_CFG_9, 0x0000003a }, - { MT_EFUSE_CTRL, 0x0000d000 }, - { MT_PAUSE_ENABLE_CONTROL1, 0x0000000a }, - { MT_FCE_WLAN_FLOW_CONTROL1, 0x60401c18 }, - { MT_WPDMA_DELAY_INT_CFG, 0x94ff0000 }, - { MT_TX_SW_CFG3, 0x00000004 }, - { MT_HT_FBK_TO_LEGACY, 0x00001818 }, - { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, - { MT_PROT_AUTO_TX_CFG, 0x00830083 }, - { MT_HT_CTRL_CFG, 0x000001ff }, - }; - struct mt76_reg_pair prot_vals[] = { - { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK }, - { MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG_OFDM }, - { MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 }, - { MT_MM40_PROT_CFG, DEFAULT_PROT_CFG_40 }, - { MT_GF20_PROT_CFG, DEFAULT_PROT_CFG_20 }, - { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, - }; - - mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals)); - mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals)); -} -EXPORT_SYMBOL_GPL(mt76_write_mac_initvals); - -void mt76x2_init_device(struct mt76x2_dev *dev) -{ - struct ieee80211_hw *hw = mt76_hw(dev); - - hw->queues = 4; - hw->max_rates = 1; - hw->max_report_rates = 7; - hw->max_rate_tries = 1; - hw->extra_tx_headroom = 2; - - hw->sta_data_size = sizeof(struct mt76x02_sta); - hw->vif_data_size = sizeof(struct mt76x02_vif); - - ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); - - dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; - dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; - - dev->mt76.chainmask = 0x202; - dev->mt76.global_wcid.idx = 255; - dev->mt76.global_wcid.hw_key_idx = -1; - dev->slottime = 9; - - /* init antenna configuration */ - dev->mt76.antenna_mask = 3; -} -EXPORT_SYMBOL_GPL(mt76x2_init_device); - -void mt76x2_init_txpower(struct mt76x2_dev *dev, - struct ieee80211_supported_band *sband) -{ - struct ieee80211_channel *chan; - struct mt76x2_tx_power_info txp; - struct mt76_rate_power t = {}; - int target_power; - int i; - - for (i = 0; i < sband->n_channels; i++) { - chan = &sband->channels[i]; - - mt76x2_get_power_info(dev, &txp, chan); - - target_power = max_t(int, (txp.chain[0].target_power + - txp.chain[0].delta), - (txp.chain[1].target_power + - txp.chain[1].delta)); - - mt76x2_get_rate_power(dev, &t, chan); - - chan->max_power = mt76x02_get_max_rate_power(&t) + - target_power; - chan->max_power /= 2; - - /* convert to combined output power on 2x2 devices */ - chan->max_power += 3; - } -} -EXPORT_SYMBOL_GPL(mt76x2_init_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c deleted file mode 100644 index bb9c0a059a6e..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_trace.h" -#include "mt76x02_util.h" - -void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) -{ - idx &= 7; - mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); - mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR, - get_unaligned_le16(addr + 4)); -} - -void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) -{ - struct mt76x02_tx_status stat = {}; - unsigned long flags; - u8 update = 1; - bool ret; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return; - - trace_mac_txstat_poll(dev); - - while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { - spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); - ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); - spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); - - if (!ret) - break; - - trace_mac_txstat_fetch(dev, &stat); - - if (!irq) { - mt76x02_send_tx_status(&dev->mt76, &stat, &update); - continue; - } - - kfifo_put(&dev->txstatus_fifo, stat); - } -} - -static void -mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, - void *txwi_ptr) -{ - struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); - struct mt76x02_txwi *txwi = txwi_ptr; - - mt76x2_mac_poll_tx_status(dev, false); - - txi->tries = 0; - txi->jiffies = jiffies; - txi->wcid = txwi->wcid; - txi->pktid = txwi->pktid; - trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); - mt76x02_tx_complete(&dev->mt76, skb); -} - -void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) -{ - struct mt76x02_tx_status stat; - u8 update = 1; - - while (kfifo_get(&dev->txstatus_fifo, &stat)) - mt76x02_send_tx_status(&dev->mt76, &stat, &update); -} - -void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush) -{ - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - - if (e->txwi) - mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); - else - dev_kfree_skb_any(e->skb); -} - -static int -mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) -{ - int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; - struct mt76x02_txwi txwi; - - if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) - return -ENOSPC; - - mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); - - mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); - offset += sizeof(txwi); - - mt76_wr_copy(dev, offset, skb->data, skb->len); - return 0; -} - -static int -__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) -{ - int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; - int beacon_addr = mt76x02_beacon_offsets[bcn_idx]; - int ret = 0; - int i; - - /* Prevent corrupt transmissions during update */ - mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); - - if (skb) { - ret = mt76_write_beacon(dev, beacon_addr, skb); - if (!ret) - dev->beacon_data_mask |= BIT(bcn_idx); - } else { - dev->beacon_data_mask &= ~BIT(bcn_idx); - for (i = 0; i < beacon_len; i += 4) - mt76_wr(dev, beacon_addr + i, 0); - } - - mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); - - return ret; -} - -int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, - struct sk_buff *skb) -{ - bool force_update = false; - int bcn_idx = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { - if (vif_idx == i) { - force_update = !!dev->beacons[i] ^ !!skb; - - if (dev->beacons[i]) - dev_kfree_skb(dev->beacons[i]); - - dev->beacons[i] = skb; - __mt76x2_mac_set_beacon(dev, bcn_idx, skb); - } else if (force_update && dev->beacons[i]) { - __mt76x2_mac_set_beacon(dev, bcn_idx, dev->beacons[i]); - } - - bcn_idx += !!dev->beacons[i]; - } - - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { - if (!(dev->beacon_data_mask & BIT(i))) - break; - - __mt76x2_mac_set_beacon(dev, i, NULL); - } - - mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, - bcn_idx - 1); - return 0; -} - -void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) -{ - u8 old_mask = dev->beacon_mask; - bool en; - u32 reg; - - if (val) { - dev->beacon_mask |= BIT(vif_idx); - } else { - dev->beacon_mask &= ~BIT(vif_idx); - mt76x2_mac_set_beacon(dev, vif_idx, NULL); - } - - if (!!old_mask == !!dev->beacon_mask) - return; - - en = dev->beacon_mask; - - mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); - reg = MT_BEACON_TIME_CFG_BEACON_TX | - MT_BEACON_TIME_CFG_TBTT_EN | - MT_BEACON_TIME_CFG_TIMER_EN; - mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); - - if (en) - mt76x02_irq_enable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); - else - mt76x02_irq_disable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); -} - -void mt76x2_update_channel(struct mt76_dev *mdev) -{ - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct mt76_channel_state *state; - u32 active, busy; - - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); - - busy = mt76_rr(dev, MT_CH_BUSY); - active = busy + mt76_rr(dev, MT_CH_IDLE); - - spin_lock_bh(&dev->mt76.cc_lock); - state->cc_busy += busy; - state->cc_active += active; - spin_unlock_bh(&dev->mt76.cc_lock); -} - -void mt76x2_mac_work(struct work_struct *work) -{ - struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev, - mac_work.work); - int i, idx; - - mt76x2_update_channel(&dev->mt76); - for (i = 0, idx = 0; i < 16; i++) { - u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); - - dev->aggr_stats[idx++] += val & 0xffff; - dev->aggr_stats[idx++] += val >> 16; - } - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, - MT_CALIBRATE_INTERVAL); -} - -void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val) -{ - u32 data = 0; - - if (val != ~0) - data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) | - MT_PROT_CFG_RTS_THRESH; - - mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val); - - mt76_rmw(dev, MT_CCK_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_OFDM_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_MM20_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_MM40_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_GF20_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_GF40_PROT_CFG, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG6, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG7, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); - mt76_rmw(dev, MT_TX_PROT_CFG8, - MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h deleted file mode 100644 index 66a57294fcfc..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 __MT76x2_MAC_H -#define __MT76x2_MAC_H - -#include "mt76.h" -#include "mt76x02_mac.h" - -struct mt76x2_dev; -struct mt76x2_sta; -struct mt76x02_vif; - -struct mt76x2_tx_info { - unsigned long jiffies; - u8 tries; - - u8 wcid; - u8 pktid; - u8 retry; -}; - -static inline struct mt76x2_tx_info * -mt76x2_skb_tx_info(struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - return (void *) info->status.status_driver_data; -} - -int mt76x2_mac_start(struct mt76x2_dev *dev); -void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force); -void mt76x2_mac_resume(struct mt76x2_dev *dev); -void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); - -int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, - void *rxi); -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, int len); - -int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, - struct sk_buff *skb); -void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val); - -void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq); -void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev); - -void mt76x2_mac_work(struct work_struct *work); - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c deleted file mode 100644 index ed4f56a3aae9..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "mt76x02_util.h" - -void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) -{ - bool stopped = false; - u32 rts_cfg; - int i; - - mt76_wr(dev, MT_MAC_SYS_CTRL, 0); - - rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); - mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); - - /* Wait for MAC to become idle */ - for (i = 0; i < 300; i++) { - if ((mt76_rr(dev, MT_MAC_STATUS) & - (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || - mt76_rr(dev, MT_BBP(IBI, 12))) { - udelay(1); - continue; - } - - stopped = true; - break; - } - - if (force && !stopped) { - mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); - mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); - - mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); - mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); - } - - mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_stop); - -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, int len) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct ieee80211_key_conf *key = info->control.hw_key; - u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); - u8 nss; - s8 txpwr_adj, max_txpwr_adj; - u8 ccmp_pn[8]; - - memset(txwi, 0, sizeof(*txwi)); - - if (wcid) - txwi->wcid = wcid->idx; - else - txwi->wcid = 0xff; - - txwi->pktid = 1; - - if (wcid && wcid->sw_iv && key) { - u64 pn = atomic64_inc_return(&key->tx_pn); - ccmp_pn[0] = pn; - ccmp_pn[1] = pn >> 8; - ccmp_pn[2] = 0; - ccmp_pn[3] = 0x20 | (key->keyidx << 6); - ccmp_pn[4] = pn >> 16; - ccmp_pn[5] = pn >> 24; - ccmp_pn[6] = pn >> 32; - ccmp_pn[7] = pn >> 40; - txwi->iv = *((__le32 *)&ccmp_pn[0]); - txwi->eiv = *((__le32 *)&ccmp_pn[1]); - } - - spin_lock_bh(&dev->mt76.lock); - if (wcid && (rate->idx < 0 || !rate->count)) { - txwi->rate = wcid->tx_rate; - max_txpwr_adj = wcid->max_txpwr_adj; - nss = wcid->tx_rate_nss; - } else { - txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); - max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(&dev->mt76, rate); - } - spin_unlock_bh(&dev->mt76.lock); - - txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, - max_txpwr_adj); - txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); - - if (mt76xx_rev(dev) >= MT76XX_REV_E4) - txwi->txstream = 0x13; - else if (mt76xx_rev(dev) >= MT76XX_REV_E3 && - !(txwi->rate & cpu_to_le16(rate_ht_mask))) - txwi->txstream = 0x93; - - mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); - -int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) -{ - struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; - - rssi += cal->rssi_offset[chain]; - rssi -= cal->lna_gain; - - return rssi; -} - -static struct mt76x02_sta * -mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) -{ - struct mt76_wcid *wcid; - - if (idx >= ARRAY_SIZE(dev->mt76.wcid)) - return NULL; - - wcid = rcu_dereference(dev->mt76.wcid[idx]); - if (!wcid) - return NULL; - - return container_of(wcid, struct mt76x02_sta, wcid); -} - -static struct mt76_wcid * -mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x02_sta *sta, - bool unicast) -{ - if (!sta) - return NULL; - - if (unicast) - return &sta->wcid; - else - return &sta->vif->group_wcid; -} - -int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, - void *rxi) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct mt76x02_rxwi *rxwi = rxi; - struct mt76x02_sta *sta; - u32 rxinfo = le32_to_cpu(rxwi->rxinfo); - u32 ctl = le32_to_cpu(rxwi->ctl); - u16 rate = le16_to_cpu(rxwi->rate); - u16 tid_sn = le16_to_cpu(rxwi->tid_sn); - bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); - int pad_len = 0; - u8 pn_len; - u8 wcid; - int len; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return -EINVAL; - - if (rxinfo & MT_RXINFO_L2PAD) - pad_len += 2; - - if (rxinfo & MT_RXINFO_DECRYPT) { - status->flag |= RX_FLAG_DECRYPTED; - status->flag |= RX_FLAG_MMIC_STRIPPED; - status->flag |= RX_FLAG_MIC_STRIPPED; - status->flag |= RX_FLAG_IV_STRIPPED; - } - - wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); - sta = mt76x2_rx_get_sta(dev, wcid); - status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast); - - len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); - pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); - if (pn_len) { - int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; - u8 *data = skb->data + offset; - - status->iv[0] = data[7]; - status->iv[1] = data[6]; - status->iv[2] = data[5]; - status->iv[3] = data[4]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - /* - * Driver CCMP validation can't deal with fragments. - * Let mac80211 take care of it. - */ - if (rxinfo & MT_RXINFO_FRAG) { - status->flag &= ~RX_FLAG_IV_STRIPPED; - } else { - pad_len += pn_len << 2; - len -= pn_len << 2; - } - } - - mt76x02_remove_hdr_pad(skb, pad_len); - - if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) - status->aggr = true; - - if (WARN_ON_ONCE(len > skb->len)) - return -EINVAL; - - pskb_trim(skb, len); - status->chains = BIT(0) | BIT(1); - status->chain_signal[0] = mt76x2_mac_get_rssi(dev, rxwi->rssi[0], 0); - status->chain_signal[1] = mt76x2_mac_get_rssi(dev, rxwi->rssi[1], 1); - status->signal = max(status->chain_signal[0], status->chain_signal[1]); - status->freq = dev->mt76.chandef.chan->center_freq; - status->band = dev->mt76.chandef.chan->band; - - status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); - status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); - - if (sta) { - ewma_signal_add(&sta->rssi, status->signal); - sta->inactive_count = 0; - } - - return mt76x02_mac_process_rate(status, rate); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c deleted file mode 100644 index 63691b68a436..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 "mt76x2.h" -#include "mt76x02_util.h" - -static int -mt76x2_start(struct ieee80211_hw *hw) -{ - struct mt76x2_dev *dev = hw->priv; - int ret; - - mutex_lock(&dev->mt76.mutex); - - ret = mt76x2_mac_start(dev); - if (ret) - goto out; - - ret = mt76x2_phy_start(dev); - if (ret) - goto out; - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, - MT_CALIBRATE_INTERVAL); - - set_bit(MT76_STATE_RUNNING, &dev->mt76.state); - -out: - mutex_unlock(&dev->mt76.mutex); - return ret; -} - -static void -mt76x2_stop(struct ieee80211_hw *hw) -{ - struct mt76x2_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); - mt76x2_stop_hardware(dev); - mutex_unlock(&dev->mt76.mutex); -} - -static int -mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) -{ - int ret; - - cancel_delayed_work_sync(&dev->cal_work); - - set_bit(MT76_RESET, &dev->mt76.state); - - mt76_set_channel(&dev->mt76); - - tasklet_disable(&dev->pre_tbtt_tasklet); - tasklet_disable(&dev->dfs_pd.dfs_tasklet); - - mt76x2_mac_stop(dev, true); - ret = mt76x2_phy_set_channel(dev, chandef); - - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - - mt76x2_dfs_init_params(dev); - - mt76x2_mac_resume(dev); - tasklet_enable(&dev->dfs_pd.dfs_tasklet); - tasklet_enable(&dev->pre_tbtt_tasklet); - - clear_bit(MT76_RESET, &dev->mt76.state); - - mt76_txq_schedule_all(&dev->mt76); - - return ret; -} - -static int -mt76x2_config(struct ieee80211_hw *hw, u32 changed) -{ - struct mt76x2_dev *dev = hw->priv; - int ret = 0; - - mutex_lock(&dev->mt76.mutex); - - 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); - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - dev->mt76.txpower_conf = hw->conf.power_level * 2; - - /* convert to per-chain power for 2x2 devices */ - dev->mt76.txpower_conf -= 6; - - if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { - mt76x2_phy_set_txpower(dev); - mt76x2_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); - } - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - ret = mt76x2_set_channel(dev, &hw->conf.chandef); - ieee80211_wake_queues(hw); - } - - mutex_unlock(&dev->mt76.mutex); - - return ret; -} - -static void -mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - - mutex_lock(&dev->mt76.mutex); - - if (changed & BSS_CHANGED_BSSID) - mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); - - if (changed & BSS_CHANGED_BEACON_INT) { - mt76_rmw_field(dev, MT_BEACON_TIME_CFG, - MT_BEACON_TIME_CFG_INTVAL, - info->beacon_int << 4); - dev->beacon_int = info->beacon_int; - dev->tbtt_count = 0; - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) { - tasklet_disable(&dev->pre_tbtt_tasklet); - mt76x2_mac_set_beacon_enable(dev, mvif->idx, - info->enable_beacon); - tasklet_enable(&dev->pre_tbtt_tasklet); - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - int slottime = info->use_short_slot ? 9 : 20; - - dev->slottime = slottime; - mt76x2_set_tx_ackto(dev); - } - - mutex_unlock(&dev->mt76.mutex); -} - -void -mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) -{ - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - int idx = msta->wcid.idx; - - mt76_stop_tx_queues(&dev->mt76, sta, true); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, ps); -} - -static void -mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac) -{ - struct mt76x2_dev *dev = hw->priv; - - tasklet_disable(&dev->pre_tbtt_tasklet); - set_bit(MT76_SCANNING, &dev->mt76.state); -} - -static void -mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = hw->priv; - - clear_bit(MT76_SCANNING, &dev->mt76.state); - tasklet_enable(&dev->pre_tbtt_tasklet); -} - -static void -mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) -{ -} - -static int -mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) -{ - struct mt76x2_dev *dev = hw->priv; - - *dbm = dev->mt76.txpower_cur / 2; - - /* convert from per-chain power to combined output on 2x2 devices */ - *dbm += 3; - - return 0; -} - -static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, - s16 coverage_class) -{ - struct mt76x2_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - dev->coverage_class = coverage_class; - mt76x2_set_tx_ackto(dev); - mutex_unlock(&dev->mt76.mutex); -} - -static int -mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) -{ - return 0; -} - -static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, - u32 rx_ant) -{ - struct mt76x2_dev *dev = hw->priv; - - if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) - return -EINVAL; - - mutex_lock(&dev->mt76.mutex); - - dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101; - dev->mt76.antenna_mask = tx_ant; - - mt76_set_stream_caps(&dev->mt76, true); - mt76x2_phy_set_antenna(dev); - - mutex_unlock(&dev->mt76.mutex); - - return 0; -} - -static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, - u32 *rx_ant) -{ - struct mt76x2_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - *tx_ant = dev->mt76.antenna_mask; - *rx_ant = dev->mt76.antenna_mask; - mutex_unlock(&dev->mt76.mutex); - - return 0; -} - -static int -mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -{ - struct mt76x2_dev *dev = hw->priv; - - if (val != ~0 && val > 0xffff) - return -EINVAL; - - mutex_lock(&dev->mutex); - mt76x2_mac_set_tx_protection(dev, val); - mutex_unlock(&dev->mutex); - - return 0; -} - -const struct ieee80211_ops mt76x2_ops = { - .tx = mt76x2_tx, - .start = mt76x2_start, - .stop = mt76x2_stop, - .add_interface = mt76x02_add_interface, - .remove_interface = mt76x02_remove_interface, - .config = mt76x2_config, - .configure_filter = mt76x02_configure_filter, - .bss_info_changed = mt76x2_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 = mt76x2_sw_scan, - .sw_scan_complete = mt76x2_sw_scan_complete, - .flush = mt76x2_flush, - .ampdu_action = mt76x02_ampdu_action, - .get_txpower = mt76x2_get_txpower, - .wake_tx_queue = mt76_wake_tx_queue, - .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, - .release_buffered_frames = mt76_release_buffered_frames, - .set_coverage_class = mt76x2_set_coverage_class, - .get_survey = mt76_get_survey, - .set_tim = mt76x2_set_tim, - .set_antenna = mt76x2_set_antenna, - .get_antenna = mt76x2_get_antenna, - .set_rts_threshold = mt76x2_set_rts_threshold, -}; - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c deleted file mode 100644 index 55716fd7e01d..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include -#include - -#include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_dma.h" - -static int -mt76pci_load_rom_patch(struct mt76x2_dev *dev) -{ - const struct firmware *fw = NULL; - struct mt76x02_patch_header *hdr; - bool rom_protect = !is_mt7612(dev); - int len, ret = 0; - __le32 *cur; - u32 patch_mask, patch_reg; - - if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { - dev_err(dev->mt76.dev, - "Could not get hardware semaphore for ROM PATCH\n"); - return -ETIMEDOUT; - } - - if (mt76xx_rev(dev) >= MT76XX_REV_E3) { - patch_mask = BIT(0); - patch_reg = MT_MCU_CLOCK_CTL; - } else { - patch_mask = BIT(1); - patch_reg = MT_MCU_COM_REG0; - } - - if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { - dev_info(dev->mt76.dev, "ROM patch already applied\n"); - goto out; - } - - ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev); - if (ret) - goto out; - - if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { - ret = -EIO; - dev_err(dev->mt76.dev, "Failed to load firmware\n"); - goto out; - } - - hdr = (struct mt76x02_patch_header *)fw->data; - dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); - - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); - - cur = (__le32 *) (fw->data + sizeof(*hdr)); - len = fw->size - sizeof(*hdr); - mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len); - - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - - /* Trigger ROM */ - mt76_wr(dev, MT_MCU_INT_LEVEL, 4); - - if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) { - dev_err(dev->mt76.dev, "Failed to load ROM patch\n"); - ret = -ETIMEDOUT; - } - -out: - /* release semaphore */ - if (rom_protect) - mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); - release_firmware(fw); - return ret; -} - -static int -mt76pci_load_firmware(struct mt76x2_dev *dev) -{ - const struct firmware *fw; - const struct mt76x02_fw_header *hdr; - int len, ret; - __le32 *cur; - u32 offset, val; - - ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) - goto error; - - 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) - goto error; - - 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->build_ver); - dev_info(dev->mt76.dev, "Build: %x\n", val); - dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); - - cur = (__le32 *) (fw->data + sizeof(*hdr)); - len = le32_to_cpu(hdr->ilm_len); - - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET); - mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len); - - cur += len / sizeof(*cur); - len = le32_to_cpu(hdr->dlm_len); - - if (mt76xx_rev(dev) >= MT76XX_REV_E3) - offset = MT_MCU_DLM_ADDR_E3; - else - offset = MT_MCU_DLM_ADDR; - - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); - mt76_wr_copy(dev, offset, cur, len); - - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); - if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) - mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); - - /* trigger firmware */ - mt76_wr(dev, MT_MCU_INT_LEVEL, 2); - if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) { - dev_err(dev->mt76.dev, "Firmware failed to start\n"); - release_firmware(fw); - return -ETIMEDOUT; - } - - dev_info(dev->mt76.dev, "Firmware running!\n"); - mt76x02_set_ethtool_fwver(&dev->mt76, hdr); - - release_firmware(fw); - - return ret; - -error: - dev_err(dev->mt76.dev, "Invalid firmware\n"); - release_firmware(fw); - return -ENOENT; -} - -int mt76x2_mcu_init(struct mt76x2_dev *dev) -{ - static const struct mt76_mcu_ops mt76x2_mcu_ops = { - .mcu_msg_alloc = mt76x02_mcu_msg_alloc, - .mcu_send_msg = mt76x02_mcu_msg_send, - }; - int ret; - - dev->mt76.mcu_ops = &mt76x2_mcu_ops; - - ret = mt76pci_load_rom_patch(dev); - if (ret) - return ret; - - ret = mt76pci_load_firmware(dev); - if (ret) - return ret; - - mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, true); - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h deleted file mode 100644 index fa72d5a5ecad..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 __MT76x2_MCU_H -#define __MT76x2_MCU_H - -#include "mt76x02_mcu.h" - -/* Register definitions */ -#define MT_MCU_CPU_CTL 0x0704 -#define MT_MCU_CLOCK_CTL 0x0708 -#define MT_MCU_PCIE_REMAP_BASE1 0x0740 -#define MT_MCU_PCIE_REMAP_BASE2 0x0744 -#define MT_MCU_PCIE_REMAP_BASE3 0x0748 - -#define MT_LED_CTRL 0x0770 -#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) -#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) -#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) -#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) - -#define MT_LED_TX_BLINK_0 0x0774 -#define MT_LED_TX_BLINK_1 0x0778 - -#define MT_LED_S0_BASE 0x077C -#define MT_LED_S0(_n) (MT_LED_S0_BASE + 8 * (_n)) -#define MT_LED_S1_BASE 0x0780 -#define MT_LED_S1(_n) (MT_LED_S1_BASE + 8 * (_n)) -#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) -#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ - MT_LED_STATUS_OFF_MASK) -#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) -#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ - MT_LED_STATUS_ON_MASK) -#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 8) -#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ - MT_LED_STATUS_DURATION_MASK) - -#define MT_MCU_ROM_PATCH_OFFSET 0x80000 -#define MT_MCU_ROM_PATCH_ADDR 0x90000 - -#define MT_MCU_ILM_OFFSET 0x80000 - -#define MT_MCU_DLM_OFFSET 0x100000 -#define MT_MCU_DLM_ADDR 0x90000 -#define MT_MCU_DLM_ADDR_E3 0x90800 - -enum mcu_calibration { - MCU_CAL_R = 1, - MCU_CAL_TEMP_SENSOR, - MCU_CAL_RXDCOC, - MCU_CAL_RC, - MCU_CAL_SX_LOGEN, - MCU_CAL_LC, - MCU_CAL_TX_LOFT, - MCU_CAL_TXIQ, - MCU_CAL_TSSI, - MCU_CAL_TSSI_COMP, - MCU_CAL_DPD, - MCU_CAL_RXIQC_FI, - MCU_CAL_RXIQC_FD, - MCU_CAL_PWRON, - MCU_CAL_TX_SHAPING, -}; - -enum mt76x2_mcu_cr_mode { - MT_RF_CR, - MT_BBP_CR, - MT_RF_BBP_CR, - MT_HL_TEMP_CR_UPDATE, -}; - -struct mt76x2_tssi_comp { - u8 pa_mode; - u8 cal_mode; - u16 pad; - - u8 slope0; - u8 slope1; - u8 offset0; - u8 offset1; -} __packed __aligned(4); - -int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); -int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, - bool force); - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c deleted file mode 100644 index eff483333183..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 -#include -#include - -#include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_dma.h" - -int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, - u8 bw_index, bool scan) -{ - struct sk_buff *skb; - struct { - u8 idx; - u8 scan; - u8 bw; - u8 _pad0; - - __le16 chainmask; - u8 ext_chan; - u8 _pad1; - - } __packed __aligned(4) msg = { - .idx = channel, - .scan = scan, - .bw = bw, - .chainmask = cpu_to_le16(dev->mt76.chainmask), - }; - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); - - usleep_range(5000, 10000); - - msg.ext_chan = 0xe0 + bw_index; - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); -} -EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); - -int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, - u8 channel) -{ - struct mt76_dev *mdev = &dev->mt76; - struct sk_buff *skb; - struct { - u8 cr_mode; - u8 temp; - u8 ch; - u8 _pad0; - - __le32 cfg; - } __packed __aligned(4) msg = { - .cr_mode = type, - .temp = temp_level, - .ch = channel, - }; - u32 val; - - val = BIT(31); - val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; - val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00; - msg.cfg = cpu_to_le32(val); - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); -} -EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); - -int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, - bool force) -{ - struct sk_buff *skb; - struct { - __le32 channel; - __le32 gain_val; - } __packed __aligned(4) msg = { - .channel = cpu_to_le32(channel), - .gain_val = cpu_to_le32(gain), - }; - - if (force) - msg.channel |= cpu_to_le32(BIT(31)); - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); -} -EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); - -int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, - struct mt76x2_tssi_comp *tssi_data) -{ - struct sk_buff *skb; - struct { - __le32 id; - struct mt76x2_tssi_comp data; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(MCU_CAL_TSSI_COMP), - .data = *tssi_data, - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); -} -EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c deleted file mode 100644 index 26cfda24ce08..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include -#include - -#include "mt76x2.h" -#include "mt76x2_trace.h" - -static const struct pci_device_id mt76pci_device_table[] = { - { PCI_DEVICE(0x14c3, 0x7662) }, - { PCI_DEVICE(0x14c3, 0x7612) }, - { PCI_DEVICE(0x14c3, 0x7602) }, - { }, -}; - -static int -mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct mt76x2_dev *dev; - int ret; - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); - if (ret) - return ret; - - pci_set_master(pdev); - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - dev = mt76x2_alloc_device(&pdev->dev); - if (!dev) - return -ENOMEM; - - 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_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); - - ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x2_irq_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); - if (ret) - goto error; - - ret = mt76x2_register_device(dev); - if (ret) - goto error; - - /* Fix up ASPM configuration */ - - /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ - mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); - - /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ - mt76_rmw_field(dev, 0x15a0c, 0xf << 28, 0xf); - - /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ - mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); - - return 0; - -error: - ieee80211_free_hw(mt76_hw(dev)); - return ret; -} - -static void -mt76pci_remove(struct pci_dev *pdev) -{ - struct mt76_dev *mdev = pci_get_drvdata(pdev); - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - - mt76_unregister_device(mdev); - mt76x2_cleanup(dev); - ieee80211_free_hw(mdev->hw); -} - -MODULE_DEVICE_TABLE(pci, mt76pci_device_table); -MODULE_FIRMWARE(MT7662_FIRMWARE); -MODULE_FIRMWARE(MT7662_ROM_PATCH); -MODULE_LICENSE("Dual BSD/GPL"); - -static struct pci_driver mt76pci_driver = { - .name = KBUILD_MODNAME, - .id_table = mt76pci_device_table, - .probe = mt76pci_probe, - .remove = mt76pci_remove, -}; - -module_pci_driver(mt76pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c deleted file mode 100644 index 22e66006a5f8..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 -#include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" - -static bool -mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - u32 flag = 0; - - if (!mt76x02_tssi_enabled(&dev->mt76)) - return false; - - if (mt76x2_channel_silent(dev)) - return false; - - if (chan->band == NL80211_BAND_5GHZ) - flag |= BIT(0); - - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) - flag |= BIT(8); - - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); - dev->cal.tssi_cal_done = true; - return true; -} - -static void -mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - bool is_5ghz = chan->band == NL80211_BAND_5GHZ; - - if (dev->cal.channel_cal_done) - return; - - if (mt76x2_channel_silent(dev)) - return; - - if (!dev->cal.tssi_cal_done) - mt76x2_phy_tssi_init_cal(dev); - - if (!mac_stopped) - mt76x2_mac_stop(dev, false); - - if (is_5ghz) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, true); - - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_SHAPING, 0, true); - - if (!mac_stopped) - mt76x2_mac_resume(dev); - - mt76x2_apply_gain_adj(dev); - - dev->cal.channel_cal_done = true; -} - -void mt76x2_phy_set_antenna(struct mt76x2_dev *dev) -{ - u32 val; - - val = mt76_rr(dev, MT_BBP(AGC, 0)); - val &= ~(BIT(4) | BIT(1)); - switch (dev->mt76.antenna_mask) { - case 1: - /* disable mac DAC control */ - mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); - mt76_clear(dev, MT_BBP(TXBE, 5), 3); - mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0x3); - mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 2); - /* disable DAC 1 */ - mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 4); - - val &= ~(BIT(3) | BIT(0)); - break; - case 2: - /* disable mac DAC control */ - mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); - mt76_rmw_field(dev, MT_BBP(TXBE, 5), 3, 1); - mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xc); - mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 1); - /* disable DAC 0 */ - mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 1); - - val &= ~BIT(3); - val |= BIT(0); - break; - case 3: - default: - /* enable mac DAC control */ - mt76_set(dev, MT_BBP(IBI, 9), BIT(11)); - mt76_set(dev, MT_BBP(TXBE, 5), 3); - mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xf); - mt76_clear(dev, MT_BBP(CORE, 32), GENMASK(21, 20)); - mt76_clear(dev, MT_BBP(CORE, 33), GENMASK(12, 9)); - - val &= ~BIT(0); - val |= BIT(3); - break; - } - mt76_wr(dev, MT_BBP(AGC, 0), val); -} - -static void -mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest) -{ - dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); - dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); -} - -static int -mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) -{ - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_80: - return -62; - case NL80211_CHAN_WIDTH_40: - return -65; - default: - return -68; - } -} - -static int -mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev) -{ - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_80: - return -76; - case NL80211_CHAN_WIDTH_40: - return -79; - default: - return -82; - } -} - -static void -mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) -{ - u32 val; - u8 gain_val[2]; - - gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; - gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; - - if (dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40) - val = 0x1e42 << 16; - else - val = 0x1836 << 16; - - val |= 0xf8; - - mt76_wr(dev, MT_BBP(AGC, 8), - val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); - mt76_wr(dev, MT_BBP(AGC, 9), - val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); - - if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) - mt76x2_dfs_adjust_agc(dev); -} - -static void -mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) -{ - u32 false_cca; - u8 limit = dev->cal.low_gain > 0 ? 16 : 4; - - false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); - dev->cal.false_cca = false_cca; - if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) - dev->cal.agc_gain_adjust += 2; - else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) || - (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) - dev->cal.agc_gain_adjust -= 2; - else - return; - - mt76x2_phy_set_gain_val(dev); -} - -static void -mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) -{ - u8 *gain = dev->cal.agc_gain_init; - u8 low_gain_delta, gain_delta; - bool gain_change; - int low_gain; - u32 val; - - dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); - - low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + - (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); - - gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2); - dev->cal.low_gain = low_gain; - - if (!gain_change) { - mt76x2_phy_adjust_vga_gain(dev); - return; - } - - if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) { - mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); - val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf; - if (low_gain == 2) - val |= 0x3; - else - val |= 0x5; - mt76_wr(dev, MT_BBP(AGC, 26), val); - } else { - mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); - } - - if (mt76x2_has_ext_lna(dev)) - low_gain_delta = 10; - else - low_gain_delta = 14; - - if (low_gain == 2) { - mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); - mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); - mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); - gain_delta = low_gain_delta; - dev->cal.agc_gain_adjust = 0; - } else { - mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); - if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) - mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014); - else - mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116); - mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C); - gain_delta = 0; - dev->cal.agc_gain_adjust = low_gain_delta; - } - - dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; - dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; - mt76x2_phy_set_gain_val(dev); - - /* clear false CCA counters */ - mt76_rr(dev, MT_RX_STAT_1); -} - -int mt76x2_phy_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef) -{ - struct ieee80211_channel *chan = chandef->chan; - bool scan = test_bit(MT76_SCANNING, &dev->mt76.state); - enum nl80211_band band = chan->band; - u8 channel; - - u32 ext_cca_chan[4] = { - [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(0)), - [1] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(1)), - [2] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(2)), - [3] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(3)), - }; - int ch_group_index; - u8 bw, bw_index; - int freq, freq1; - int ret; - - dev->cal.channel_cal_done = false; - freq = chandef->chan->center_freq; - freq1 = chandef->center_freq1; - channel = chan->hw_value; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_40: - bw = 1; - if (freq1 > freq) { - bw_index = 1; - ch_group_index = 0; - } else { - bw_index = 3; - ch_group_index = 1; - } - channel += 2 - ch_group_index * 4; - break; - case NL80211_CHAN_WIDTH_80: - ch_group_index = (freq - freq1 + 30) / 20; - if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) - ch_group_index = 0; - bw = 2; - bw_index = ch_group_index; - channel += 6 - ch_group_index * 4; - break; - default: - bw = 0; - bw_index = 0; - ch_group_index = 0; - break; - } - - mt76x2_read_rx_gain(dev); - mt76x2_phy_set_txpower_regs(dev, band); - mt76x2_configure_tx_delay(dev, band, bw); - mt76x2_phy_set_txpower(dev); - - mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); - mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); - - mt76_rmw(dev, MT_EXT_CCA_CFG, - (MT_EXT_CCA_CFG_CCA0 | - MT_EXT_CCA_CFG_CCA1 | - MT_EXT_CCA_CFG_CCA2 | - MT_EXT_CCA_CFG_CCA3 | - MT_EXT_CCA_CFG_CCA_MASK), - ext_cca_chan[ch_group_index]); - - ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); - if (ret) - return ret; - - mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); - - mt76x2_phy_set_antenna(dev); - - /* Enable LDPC Rx */ - if (mt76xx_rev(dev) >= MT76XX_REV_E3) - mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); - - if (!dev->cal.init_cal_done) { - u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); - - if (val != 0xff) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); - } - - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, true); - - /* Rx LPF calibration */ - if (!dev->cal.init_cal_done) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, true); - - dev->cal.init_cal_done = true; - - mt76_wr(dev, MT_BBP(AGC, 61), 0xFF64A4E2); - mt76_wr(dev, MT_BBP(AGC, 7), 0x08081010); - mt76_wr(dev, MT_BBP(AGC, 11), 0x00000404); - mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); - mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x04101B3F); - - if (scan) - return 0; - - dev->cal.low_gain = -1; - mt76x2_phy_channel_calibrate(dev, true); - mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init); - memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, - sizeof(dev->cal.agc_gain_cur)); - - /* init default values for temp compensation */ - if (mt76x02_tssi_enabled(&dev->mt76)) { - mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, - 0x38); - mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, - 0x38); - } - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, - MT_CALIBRATE_INTERVAL); - - return 0; -} - -static void -mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) -{ - struct mt76x2_temp_comp t; - int temp, db_diff; - - if (mt76x2_get_temp_comp(dev, &t)) - return; - - temp = mt76_get_field(dev, MT_TEMP_SENSOR, MT_TEMP_SENSOR_VAL); - temp -= t.temp_25_ref; - temp = (temp * 1789) / 1000 + 25; - dev->cal.temp = temp; - - if (temp > 25) - db_diff = (temp - 25) / t.high_slope; - else - db_diff = (25 - temp) / t.low_slope; - - db_diff = min(db_diff, t.upper_bound); - db_diff = max(db_diff, t.lower_bound); - - mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, - db_diff * 2); - mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, - db_diff * 2); -} - -void mt76x2_phy_calibrate(struct work_struct *work) -{ - struct mt76x2_dev *dev; - - dev = container_of(work, struct mt76x2_dev, cal_work.work); - mt76x2_phy_channel_calibrate(dev, false); - mt76x2_phy_tssi_compensate(dev, true); - mt76x2_phy_temp_compensate(dev); - mt76x2_phy_update_channel_gain(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, - MT_CALIBRATE_INTERVAL); -} - -int mt76x2_phy_start(struct mt76x2_dev *dev) -{ - int ret; - - ret = mt76x02_mcu_set_radio_state(&dev->mt76, true, true); - if (ret) - return ret; - - mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); - - return ret; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c deleted file mode 100644 index dd32e756d8b7..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_mcu.h" -#include "mt76x02_phy.h" - -static void -mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) -{ - s8 gain; - - gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); - gain -= offset / 2; - mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); -} - -static void -mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset) -{ - s8 gain; - - gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); - gain += offset; - mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); -} - -void mt76x2_apply_gain_adj(struct mt76x2_dev *dev) -{ - s8 *gain_adj = dev->cal.rx.high_gain; - - mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]); - mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]); - - mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]); - mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]); -} -EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj); - -void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, - enum nl80211_band band) -{ - u32 pa_mode[2]; - u32 pa_mode_adj; - - if (band == NL80211_BAND_2GHZ) { - pa_mode[0] = 0x010055ff; - pa_mode[1] = 0x00550055; - - mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); - mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); - - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { - mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); - mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); - } else { - mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200); - mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200); - } - } else { - pa_mode[0] = 0x0000ffff; - pa_mode[1] = 0x00ff00ff; - - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { - mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); - mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); - } else { - mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); - mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); - } - - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) - pa_mode_adj = 0x04000000; - else - pa_mode_adj = 0; - - mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj); - mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj); - } - - mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]); - mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]); - mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); - mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); - - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { - u32 val; - - if (band == NL80211_BAND_2GHZ) - val = 0x3c3c023c; - else - val = 0x363c023c; - - mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); - mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); - mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818); - } else { - if (band == NL80211_BAND_2GHZ) { - u32 val = 0x0f3c3c3c; - - mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); - mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); - mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606); - } else { - mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c); - mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28); - mt76_wr(dev, MT_TX_ALC_CFG_4, 0); - } - } -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); - -static int -mt76x2_get_min_rate_power(struct mt76_rate_power *r) -{ - int i; - s8 ret = 0; - - for (i = 0; i < sizeof(r->all); i++) { - if (!r->all[i]) - continue; - - if (ret) - ret = min(ret, r->all[i]); - else - ret = r->all[i]; - } - - return ret; -} - -void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) -{ - enum nl80211_chan_width width = dev->mt76.chandef.width; - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - struct mt76x2_tx_power_info txp; - int txp_0, txp_1, delta = 0; - struct mt76_rate_power t = {}; - int base_power, gain; - - mt76x2_get_power_info(dev, &txp, chan); - - if (width == NL80211_CHAN_WIDTH_40) - delta = txp.delta_bw40; - else if (width == NL80211_CHAN_WIDTH_80) - delta = txp.delta_bw80; - - mt76x2_get_rate_power(dev, &t, chan); - mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power); - mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf); - dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t); - - base_power = mt76x2_get_min_rate_power(&t); - delta += base_power - txp.chain[0].target_power; - txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta; - txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta; - - gain = min(txp_0, txp_1); - if (gain < 0) { - base_power -= gain; - txp_0 -= gain; - txp_1 -= gain; - } else if (gain > 0x2f) { - base_power -= gain - 0x2f; - txp_0 = 0x2f; - txp_1 = 0x2f; - } - - mt76x02_add_rate_power_offset(&t, -base_power); - dev->target_power = txp.chain[0].target_power; - dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; - dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; - dev->mt76.rate_power = t; - - mt76x02_phy_set_txpower(&dev->mt76, txp_0, txp_1); -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); - -void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, - enum nl80211_band band, u8 bw) -{ - u32 cfg0, cfg1; - - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { - cfg0 = bw ? 0x000b0c01 : 0x00101101; - cfg1 = 0x00011414; - } else { - cfg0 = bw ? 0x000b0b01 : 0x00101001; - cfg1 = 0x00021414; - } - mt76_wr(dev, MT_TX_SW_CFG0, cfg0); - mt76_wr(dev, MT_TX_SW_CFG1, cfg1); - - mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15); -} -EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); - -void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl) -{ - int core_val, agc_val; - - switch (width) { - case NL80211_CHAN_WIDTH_80: - core_val = 3; - agc_val = 7; - break; - case NL80211_CHAN_WIDTH_40: - core_val = 2; - agc_val = 3; - break; - default: - core_val = 0; - agc_val = 1; - break; - } - - mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); - mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw); - -void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) -{ - switch (band) { - case NL80211_BAND_2GHZ: - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - break; - case NL80211_BAND_5GHZ: - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - break; - } - - mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, - primary_upper); -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); - -int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) -{ - struct mt76x02_sta *sta; - struct mt76_wcid *wcid; - int i, j, min_rssi = 0; - s8 cur_rssi; - - local_bh_disable(); - rcu_read_lock(); - - for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { - unsigned long mask = dev->mt76.wcid_mask[i]; - - if (!mask) - continue; - - for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { - if (!(mask & 1)) - continue; - - wcid = rcu_dereference(dev->mt76.wcid[j]); - if (!wcid) - continue; - - sta = container_of(wcid, struct mt76x02_sta, wcid); - spin_lock(&dev->mt76.rx_lock); - if (sta->inactive_count++ < 5) - cur_rssi = ewma_signal_read(&sta->rssi); - else - cur_rssi = 0; - spin_unlock(&dev->mt76.rx_lock); - - if (cur_rssi < min_rssi) - min_rssi = cur_rssi; - } - } - - rcu_read_unlock(); - local_bh_enable(); - - if (!min_rssi) - return -75; - - return min_rssi; -} -EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi); - -void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - struct mt76x2_tx_power_info txp; - struct mt76x2_tssi_comp t = {}; - - if (!dev->cal.tssi_cal_done) - return; - - if (!dev->cal.tssi_comp_pending) { - /* TSSI trigger */ - t.cal_mode = BIT(0); - mt76x2_mcu_tssi_comp(dev, &t); - dev->cal.tssi_comp_pending = true; - } else { - if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) - return; - - dev->cal.tssi_comp_pending = false; - mt76x2_get_power_info(dev, &txp, chan); - - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) - t.pa_mode = 1; - - t.cal_mode = BIT(1); - t.slope0 = txp.chain[0].tssi_slope; - t.offset0 = txp.chain[0].tssi_offset; - t.slope1 = txp.chain[1].tssi_slope; - t.offset1 = txp.chain[1].tssi_offset; - mt76x2_mcu_tssi_comp(dev, &t); - - if (t.pa_mode || dev->cal.dpd_cal_done) - return; - - usleep_range(10000, 20000); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, - chan->hw_value, wait); - dev->cal.dpd_cal_done = true; - } -} -EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c deleted file mode 100644 index a09f117848d6..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 - -#ifndef __CHECKER__ -#define CREATE_TRACE_POINTS -#include "mt76x2_trace.h" - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h deleted file mode 100644 index eb5afeaefa44..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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. - */ - -#if !defined(__MT76x2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define __MT76x2_TRACE_H - -#include -#include "mt76x2.h" - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM mt76x2 - -#define MAXNAME 32 -#define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) -#define DEV_PR_FMT "%s" -#define DEV_PR_ARG __entry->wiphy_name - -#define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) -#define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid -#define TXID_PR_FMT " [%d:%d]" -#define TXID_PR_ARG __entry->wcid, __entry->pktid - -DECLARE_EVENT_CLASS(dev_evt, - TP_PROTO(struct mt76x2_dev *dev), - TP_ARGS(dev), - TP_STRUCT__entry( - DEV_ENTRY - ), - TP_fast_assign( - DEV_ASSIGN; - ), - TP_printk(DEV_PR_FMT, DEV_PR_ARG) -); - -DECLARE_EVENT_CLASS(dev_txid_evt, - TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), - TP_ARGS(dev, wcid, pktid), - TP_STRUCT__entry( - DEV_ENTRY - TXID_ENTRY - ), - TP_fast_assign( - DEV_ASSIGN; - TXID_ASSIGN; - ), - TP_printk( - DEV_PR_FMT TXID_PR_FMT, - DEV_PR_ARG, TXID_PR_ARG - ) -); - -DEFINE_EVENT(dev_evt, mac_txstat_poll, - TP_PROTO(struct mt76x2_dev *dev), - TP_ARGS(dev) -); - -DEFINE_EVENT(dev_txid_evt, mac_txdone_add, - TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), - TP_ARGS(dev, wcid, pktid) -); - -TRACE_EVENT(mac_txstat_fetch, - TP_PROTO(struct mt76x2_dev *dev, - struct mt76x02_tx_status *stat), - - TP_ARGS(dev, stat), - - TP_STRUCT__entry( - DEV_ENTRY - TXID_ENTRY - __field(bool, success) - __field(bool, aggr) - __field(bool, ack_req) - __field(u16, rate) - __field(u8, retry) - ), - - TP_fast_assign( - DEV_ASSIGN; - __entry->success = stat->success; - __entry->aggr = stat->aggr; - __entry->ack_req = stat->ack_req; - __entry->wcid = stat->wcid; - __entry->pktid = stat->pktid; - __entry->rate = stat->rate; - __entry->retry = stat->retry; - ), - - TP_printk( - DEV_PR_FMT TXID_PR_FMT - " success:%d aggr:%d ack_req:%d" - " rate:%04x retry:%d", - DEV_PR_ARG, TXID_PR_ARG, - __entry->success, __entry->aggr, __entry->ack_req, - __entry->rate, __entry->retry - ) -); - - -TRACE_EVENT(dev_irq, - TP_PROTO(struct mt76x2_dev *dev, u32 val, u32 mask), - - TP_ARGS(dev, val, mask), - - TP_STRUCT__entry( - DEV_ENTRY - __field(u32, val) - __field(u32, mask) - ), - - TP_fast_assign( - DEV_ASSIGN; - __entry->val = val; - __entry->mask = mask; - ), - - TP_printk( - DEV_PR_FMT " %08x & %08x", - DEV_PR_ARG, __entry->val, __entry->mask - ) -); - -#endif - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE mt76x2_trace - -#include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c deleted file mode 100644 index fcdf1879162e..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * 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 "mt76x2.h" -#include "mt76x02_util.h" -#include "mt76x02_dma.h" - -struct beacon_bc_data { - struct mt76x2_dev *dev; - struct sk_buff_head q; - struct sk_buff *tail[8]; -}; - -int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info) -{ - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int qsel = MT_QSEL_EDCA; - int ret; - - if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) - mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); - - mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); - - ret = mt76x02_insert_hdr_pad(skb); - if (ret < 0) - return ret; - - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - qsel = MT_QSEL_MGMT; - - *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | - MT_TXD_INFO_80211; - - if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) - *tx_info |= MT_TXD_INFO_WIV; - - return 0; -} - -static void -mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *) priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct sk_buff *skb = NULL; - - if (!(dev->beacon_mask & BIT(mvif->idx))) - return; - - skb = ieee80211_beacon_get(mt76_hw(dev), vif); - if (!skb) - return; - - mt76x2_mac_set_beacon(dev, mvif->idx, skb); -} - -static void -mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) -{ - struct beacon_bc_data *data = priv; - struct mt76x2_dev *dev = data->dev; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct ieee80211_tx_info *info; - struct sk_buff *skb; - - if (!(dev->beacon_mask & BIT(mvif->idx))) - return; - - skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); - if (!skb) - return; - - info = IEEE80211_SKB_CB(skb); - info->control.vif = vif; - info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; - mt76_skb_set_moredata(skb, true); - __skb_queue_tail(&data->q, skb); - data->tail[mvif->idx] = skb; -} - -static void -mt76x2_resync_beacon_timer(struct mt76x2_dev *dev) -{ - u32 timer_val = dev->beacon_int << 4; - - dev->tbtt_count++; - - /* - * Beacon timer drifts by 1us every tick, the timer is configured - * in 1/16 TU (64us) units. - */ - if (dev->tbtt_count < 62) - return; - - if (dev->tbtt_count >= 64) { - dev->tbtt_count = 0; - return; - } - - /* - * The updated beacon interval takes effect after two TBTT, because - * at this point the original interval has already been loaded into - * the next TBTT_TIMER value - */ - if (dev->tbtt_count == 62) - timer_val -= 1; - - mt76_rmw_field(dev, MT_BEACON_TIME_CFG, - MT_BEACON_TIME_CFG_INTVAL, timer_val); -} - -void mt76x2_pre_tbtt_tasklet(unsigned long arg) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *) arg; - struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD]; - struct beacon_bc_data data = {}; - struct sk_buff *skb; - int i, nframes; - - mt76x2_resync_beacon_timer(dev); - - data.dev = dev; - __skb_queue_head_init(&data.q); - - ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), - IEEE80211_IFACE_ITER_RESUME_ALL, - mt76x2_update_beacon_iter, dev); - - do { - nframes = skb_queue_len(&data.q); - ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), - IEEE80211_IFACE_ITER_RESUME_ALL, - mt76x2_add_buffered_bc, &data); - } while (nframes != skb_queue_len(&data.q)); - - if (!nframes) - return; - - for (i = 0; i < ARRAY_SIZE(data.tail); i++) { - if (!data.tail[i]) - continue; - - mt76_skb_set_moredata(data.tail[i], false); - } - - spin_lock_bh(&q->lock); - while ((skb = __skb_dequeue(&data.q)) != NULL) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - - mt76_dma_tx_queue_skb(&dev->mt76, q, skb, &mvif->group_wcid, - NULL); - } - spin_unlock_bh(&q->lock); -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c deleted file mode 100644 index 1ec3c293e2c4..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2.h" -#include "dma.h" - -void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x2_dev *dev = hw->priv; - struct ieee80211_vif *vif = info->control.vif; - struct mt76_wcid *wcid = &dev->mt76.global_wcid; - - if (control->sta) { - struct mt76x02_sta *msta; - - msta = (struct mt76x02_sta *)control->sta->drv_priv; - wcid = &msta->wcid; - /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != 0xff) - control->sta = NULL; - } - - if (vif && !control->sta) { - struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *)vif->drv_priv; - wcid = &mvif->group_wcid; - } - - mt76_tx(&dev->mt76, control->sta, wcid, skb); -} -EXPORT_SYMBOL_GPL(mt76x2_tx); - -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, - const struct ieee80211_tx_rate *rate) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *) mdev; - s8 max_txpwr; - - if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - u8 mcs = ieee80211_rate_get_vht_mcs(rate); - - if (mcs == 8 || mcs == 9) { - max_txpwr = mdev->rate_power.vht[8]; - } else { - u8 nss, idx; - - nss = ieee80211_rate_get_vht_nss(rate); - idx = ((nss - 1) << 3) + mcs; - max_txpwr = mdev->rate_power.ht[idx & 0xf]; - } - } else if (rate->flags & IEEE80211_TX_RC_MCS) { - max_txpwr = mdev->rate_power.ht[rate->idx & 0xf]; - } else { - enum nl80211_band band = dev->mt76.chandef.chan->band; - - if (band == NL80211_BAND_2GHZ) { - const struct ieee80211_rate *r; - struct wiphy *wiphy = mt76_hw(dev)->wiphy; - struct mt76_rate_power *rp = &mdev->rate_power; - - r = &wiphy->bands[band]->bitrates[rate->idx]; - if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) - max_txpwr = rp->cck[r->hw_value & 0x3]; - else - max_txpwr = rp->ofdm[r->hw_value & 0x7]; - } else { - max_txpwr = mdev->rate_power.ofdm[rate->idx & 0x7]; - } - } - - return max_txpwr; -} -EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj); - -s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) -{ - txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); - txpwr -= (dev->target_power + dev->target_power_delta[0]); - txpwr = min_t(s8, txpwr, max_txpwr_adj); - - if (!dev->enable_tpc) - return 0; - else if (txpwr >= 0) - return min_t(s8, txpwr, 7); - else - return (txpwr < -16) ? 8 : (txpwr + 32) / 2; -} -EXPORT_SYMBOL_GPL(mt76x2_tx_get_txpwr_adj); - -void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) -{ - s8 txpwr_adj; - - txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, - dev->mt76.rate_power.ofdm[4]); - mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, - MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); - mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, - MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); -} -EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c deleted file mode 100644 index feb5cec66c67..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 -#include - -#include "mt76x02_usb.h" -#include "mt76x2u.h" - -static const struct usb_device_id mt76x2u_device_table[] = { - { USB_DEVICE(0x0e8d, 0x7612) }, /* Alfa AWUS036ACM */ - { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ - { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ - { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ - { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USB-AC1200 */ - { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ - { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ - { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ - { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ - { }, -}; - -static int mt76x2u_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct mt76x2_dev *dev; - int err; - - dev = mt76x2u_alloc_device(&intf->dev); - if (!dev) - return -ENOMEM; - - udev = usb_get_dev(udev); - usb_reset_device(udev); - - mt76x02u_init_mcu(&dev->mt76); - err = mt76u_init(&dev->mt76, intf); - if (err < 0) - goto err; - - dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); - dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); - - err = mt76x2u_register_device(dev); - if (err < 0) - goto err; - - return 0; - -err: - ieee80211_free_hw(mt76_hw(dev)); - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - - return err; -} - -static void mt76x2u_disconnect(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct mt76x2_dev *dev = usb_get_intfdata(intf); - struct ieee80211_hw *hw = mt76_hw(dev); - - set_bit(MT76_REMOVED, &dev->mt76.state); - ieee80211_unregister_hw(hw); - mt76x2u_cleanup(dev); - - ieee80211_free_hw(hw); - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); -} - -static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, - pm_message_t state) -{ - struct mt76x2_dev *dev = usb_get_intfdata(intf); - struct mt76_usb *usb = &dev->mt76.usb; - - mt76u_stop_queues(&dev->mt76); - mt76x2u_stop_hw(dev); - usb_kill_urb(usb->mcu.res.urb); - - return 0; -} - -static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) -{ - struct mt76x2_dev *dev = usb_get_intfdata(intf); - struct mt76_usb *usb = &dev->mt76.usb; - int err; - - reinit_completion(&usb->mcu.cmpl); - err = mt76u_submit_buf(&dev->mt76, USB_DIR_IN, - MT_EP_IN_CMD_RESP, - &usb->mcu.res, GFP_KERNEL, - mt76u_mcu_complete_urb, - &usb->mcu.cmpl); - if (err < 0) - goto err; - - err = mt76u_submit_rx_buffers(&dev->mt76); - if (err < 0) - goto err; - - tasklet_enable(&usb->rx_tasklet); - tasklet_enable(&usb->tx_tasklet); - - err = mt76x2u_init_hardware(dev); - if (err < 0) - goto err; - - return 0; - -err: - mt76x2u_cleanup(dev); - return err; -} - -MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); -MODULE_FIRMWARE(MT7662U_FIRMWARE); -MODULE_FIRMWARE(MT7662U_ROM_PATCH); - -static struct usb_driver mt76x2u_driver = { - .name = KBUILD_MODNAME, - .id_table = mt76x2u_device_table, - .probe = mt76x2u_probe, - .disconnect = mt76x2u_disconnect, -#ifdef CONFIG_PM - .suspend = mt76x2u_suspend, - .resume = mt76x2u_resume, - .reset_resume = mt76x2u_resume, -#endif /* CONFIG_PM */ - .soft_unbind = 1, - .disable_hub_initiated_lpm = 1, -}; -module_usb_driver(mt76x2u_driver); - -MODULE_AUTHOR("Lorenzo Bianconi "); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h deleted file mode 100644 index 5d2ebdf42c63..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 __MT76x2U_H -#define __MT76x2U_H - -#include - -#include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x02_dma.h" - -#define MT7612U_EEPROM_SIZE 512 - -#define MT_USB_AGGR_SIZE_LIMIT 21 /* 1024B unit */ -#define MT_USB_AGGR_TIMEOUT 0x80 /* 33ns unit */ - -extern const struct ieee80211_ops mt76x2u_ops; - -struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev); -int mt76x2u_register_device(struct mt76x2_dev *dev); -int mt76x2u_init_hardware(struct mt76x2_dev *dev); -void mt76x2u_cleanup(struct mt76x2_dev *dev); -void mt76x2u_stop_hw(struct mt76x2_dev *dev); - -int mt76x2u_mac_reset(struct mt76x2_dev *dev); -void mt76x2u_mac_resume(struct mt76x2_dev *dev); -int mt76x2u_mac_start(struct mt76x2_dev *dev); -int mt76x2u_mac_stop(struct mt76x2_dev *dev); - -int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef); -void mt76x2u_phy_calibrate(struct work_struct *work); -void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev); - -void mt76x2u_mcu_complete_urb(struct urb *urb); -int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, - bool ext, int rssi, u32 false_cca); -int mt76x2u_mcu_init(struct mt76x2_dev *dev); -int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); - -int mt76x2u_alloc_queues(struct mt76x2_dev *dev); -void mt76x2u_queues_deinit(struct mt76x2_dev *dev); -void mt76x2u_stop_queues(struct mt76x2_dev *dev); -int mt76x2u_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); -int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, - u32 flags); - -#endif /* __MT76x2U_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c deleted file mode 100644 index c2ccdebca470..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2u.h" -#include "dma.h" -#include "mt76x02_util.h" -#include "mt76x02_usb.h" - -static int -mt76x2u_check_skb_rooms(struct sk_buff *skb) -{ - int hdr_len = ieee80211_get_hdrlen_from_skb(skb); - u32 need_head; - - need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; - if (hdr_len % 4) - need_head += 2; - return skb_cow(skb, need_head); -} - -int mt76x2u_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 mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct mt76x02_txwi *txwi; - int err, len = skb->len; - - err = mt76x2u_check_skb_rooms(skb); - if (err < 0) - return -ENOMEM; - - mt76x02_insert_hdr_pad(skb); - - txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); - mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); - - return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c deleted file mode 100644 index 5759a72d7ef6..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 - -#include "mt76x2u.h" -#include "mt76x02_util.h" -#include "mt76x02_phy.h" -#include "mt76x2_eeprom.h" - -static void mt76x2u_init_dma(struct mt76x2_dev *dev) -{ - u32 val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); - - val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD | - 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_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); -} - -static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev) -{ - mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) | BIT(16)); - udelay(1); - - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1c), 0xff); - mt76_set(dev, MT_VEND_ADDR(CFG, 0x1c), 0x30); - - mt76_wr(dev, MT_VEND_ADDR(CFG, 0x14), 0x484f); - udelay(1); - - mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(17)); - usleep_range(150, 200); - - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(16)); - usleep_range(50, 100); - - mt76_set(dev, MT_VEND_ADDR(CFG, 0x14c), BIT(19) | BIT(20)); -} - -static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit) -{ - int shift = unit ? 8 : 0; - u32 val = (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift; - - /* Enable RF BG */ - mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) << shift); - usleep_range(10, 20); - - /* Enable RFDIG LDO/AFE/ABB/ADDA */ - mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), val); - usleep_range(10, 20); - - /* Switch RFDIG power to internal LDO */ - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(2) << shift); - usleep_range(10, 20); - - mt76x2u_power_on_rf_patch(dev); - - mt76_set(dev, 0x530, 0xf); -} - -static void mt76x2u_power_on(struct mt76x2_dev *dev) -{ - u32 val; - - /* Turn on WL MTCMOS */ - mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), - MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); - - val = MT_WLAN_MTC_CTRL_STATE_UP | - MT_WLAN_MTC_CTRL_PWR_ACK | - MT_WLAN_MTC_CTRL_PWR_ACK_S; - - mt76_poll(dev, MT_VEND_ADDR(CFG, 0x148), val, val, 1000); - - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0x7f << 16); - usleep_range(10, 20); - - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); - usleep_range(10, 20); - - mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xfff); - - /* Turn on AD/DA power down */ - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1204), BIT(3)); - - /* WLAN function enable */ - mt76_set(dev, MT_VEND_ADDR(CFG, 0x80), BIT(0)); - - /* Release BBP software reset */ - mt76_clear(dev, MT_VEND_ADDR(CFG, 0x64), BIT(18)); - - mt76x2u_power_on_rf(dev, 0); - mt76x2u_power_on_rf(dev, 1); -} - -static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) -{ - u32 val, i; - - dev->mt76.eeprom.data = devm_kzalloc(dev->mt76.dev, - MT7612U_EEPROM_SIZE, - GFP_KERNEL); - dev->mt76.eeprom.size = MT7612U_EEPROM_SIZE; - if (!dev->mt76.eeprom.data) - return -ENOMEM; - - for (i = 0; i + 4 <= MT7612U_EEPROM_SIZE; i += 4) { - val = mt76_rr(dev, MT_VEND_ADDR(EEPROM, i)); - put_unaligned_le32(val, dev->mt76.eeprom.data + i); - } - - mt76x02_eeprom_parse_hw_cap(&dev->mt76); - return 0; -} - -struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) -{ - static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x2u_tx_prepare_skb, - .tx_complete_skb = mt76x02_tx_complete_skb, - .tx_status_data = mt76x02_tx_status_data, - .rx_skb = mt76x2_queue_rx_skb, - }; - struct mt76x2_dev *dev; - struct mt76_dev *mdev; - - mdev = mt76_alloc_device(sizeof(*dev), &mt76x2u_ops); - if (!mdev) - return NULL; - - dev = container_of(mdev, struct mt76x2_dev, mt76); - mdev->dev = pdev; - mdev->drv = &drv_ops; - - return dev; -} - -static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) -{ - mt76_wr(dev, MT_BCN_OFFSET(0), 0x18100800); - mt76_wr(dev, MT_BCN_OFFSET(1), 0x38302820); - mt76_wr(dev, MT_BCN_OFFSET(2), 0x58504840); - mt76_wr(dev, MT_BCN_OFFSET(3), 0x78706860); -} - -int mt76x2u_init_hardware(struct mt76x2_dev *dev) -{ - const struct mt76_wcid_addr addr = { - .macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - .ba_mask = 0, - }; - int i, err; - - mt76x2_reset_wlan(dev, true); - mt76x2u_power_on(dev); - - if (!mt76x02_wait_for_mac(&dev->mt76)) - return -ETIMEDOUT; - - err = mt76x2u_mcu_fw_init(dev); - if (err < 0) - return err; - - 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; - - /* wait for asic ready after fw load. */ - if (!mt76x02_wait_for_mac(&dev->mt76)) - return -ETIMEDOUT; - - mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0); - mt76_wr(dev, MT_TSO_CTRL, 0); - - mt76x2u_init_dma(dev); - - err = mt76x2u_mcu_init(dev); - if (err < 0) - return err; - - err = mt76x2u_mac_reset(dev); - if (err < 0) - return err; - - mt76x02_mac_setaddr(&dev->mt76, - dev->mt76.eeprom.data + MT_EE_MAC_ADDR); - dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); - - mt76x2u_init_beacon_offsets(dev); - - if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) - return -ETIMEDOUT; - - /* reset wcid table */ - for (i = 0; i < 254; i++) - mt76_wr_copy(dev, MT_WCID_ADDR(i), &addr, - sizeof(struct mt76_wcid_addr)); - - /* reset shared key table and pairwise key table */ - for (i = 0; i < 4; i++) - mt76_wr(dev, MT_SKEY_MODE_BASE_0 + 4 * i, 0); - for (i = 0; i < 256; i++) - mt76_wr(dev, MT_WCID_ATTR(i), 1); - - 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); - - mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); - mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f); - - err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); - if (err < 0) - return err; - - mt76x02_phy_set_rxpath(&dev->mt76); - mt76x02_phy_set_txdac(&dev->mt76); - - return mt76x2u_mac_stop(dev); -} - -int mt76x2u_register_device(struct mt76x2_dev *dev) -{ - struct ieee80211_hw *hw = mt76_hw(dev); - struct wiphy *wiphy = hw->wiphy; - int err; - - INIT_DELAYED_WORK(&dev->cal_work, mt76x2u_phy_calibrate); - mt76x2_init_device(dev); - - err = mt76x2u_init_eeprom(dev); - if (err < 0) - return err; - - err = mt76u_alloc_queues(&dev->mt76); - if (err < 0) - goto fail; - - err = mt76u_mcu_init_rx(&dev->mt76); - if (err < 0) - return err; - - err = mt76x2u_init_hardware(dev); - if (err < 0) - goto fail; - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - err = mt76_register_device(&dev->mt76, true, mt76x02_rates, - ARRAY_SIZE(mt76x02_rates)); - if (err) - goto fail; - - /* check hw sg support in order to enable AMSDU */ - if (mt76u_check_sg(&dev->mt76)) - hw->max_tx_fragments = MT_SG_MAX_SIZE; - else - hw->max_tx_fragments = 1; - - set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - - mt76x2_init_debugfs(dev); - mt76x2_init_txpower(dev, &dev->mt76.sband_2g.sband); - mt76x2_init_txpower(dev, &dev->mt76.sband_5g.sband); - - return 0; - -fail: - mt76x2u_cleanup(dev); - return err; -} - -void mt76x2u_stop_hw(struct mt76x2_dev *dev) -{ - mt76u_stop_stat_wk(&dev->mt76); - cancel_delayed_work_sync(&dev->cal_work); - mt76x2u_mac_stop(dev); -} - -void mt76x2u_cleanup(struct mt76x2_dev *dev) -{ - mt76x02_mcu_set_radio_state(&dev->mt76, false, false); - mt76x2u_stop_hw(dev); - mt76u_queues_deinit(&dev->mt76); - mt76u_mcu_deinit(&dev->mt76); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c deleted file mode 100644 index f28c6fbcc305..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2u.h" -#include "mt76x2_eeprom.h" - -static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev) -{ - mt76_rr(dev, MT_RX_STAT_0); - mt76_rr(dev, MT_RX_STAT_1); - mt76_rr(dev, MT_RX_STAT_2); - mt76_rr(dev, MT_TX_STA_0); - mt76_rr(dev, MT_TX_STA_1); - mt76_rr(dev, MT_TX_STA_2); -} - -static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) -{ - s8 offset = 0; - u16 eep_val; - - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); - - offset = eep_val & 0x7f; - if ((eep_val & 0xff) == 0xff) - offset = 0; - else if (eep_val & 0x80) - offset = 0 - offset; - - eep_val >>= 8; - if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); - eep_val &= 0xff; - - if (eep_val == 0x00 || eep_val == 0xff) - eep_val = 0x14; - } - - eep_val &= 0x7f; - mt76_rmw_field(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL5), - MT_XO_CTRL5_C2_VAL, eep_val + offset); - mt76_set(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL6), MT_XO_CTRL6_C2_CTRL); - - mt76_wr(dev, 0x504, 0x06000000); - mt76_wr(dev, 0x50c, 0x08800000); - mdelay(5); - mt76_wr(dev, 0x504, 0x0); - - /* decrease SIFS from 16us to 13us */ - mt76_rmw_field(dev, MT_XIFS_TIME_CFG, - MT_XIFS_TIME_CFG_OFDM_SIFS, 0xd); - mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, MT_BKOFF_SLOT_CFG_CC_DELAY, 1); - - /* init fce */ - mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); - - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); - switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { - case 0: - mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); - break; - case 1: - mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); - break; - default: - break; - } -} - -int mt76x2u_mac_reset(struct mt76x2_dev *dev) -{ - mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5)); - - /* init pbf regs */ - mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); - mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); - - mt76_write_mac_initvals(dev); - - mt76_wr(dev, MT_TX_LINK_CFG, 0x1020); - mt76_wr(dev, MT_AUTO_RSP_CFG, 0x13); - mt76_wr(dev, MT_MAX_LEN_CFG, 0x2f00); - mt76_wr(dev, MT_TX_RTS_CFG, 0x92b20); - - mt76_wr(dev, MT_WMM_AIFSN, 0x2273); - mt76_wr(dev, MT_WMM_CWMIN, 0x2344); - mt76_wr(dev, MT_WMM_CWMAX, 0x34aa); - - mt76_clear(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_RESET_CSR | - MT_MAC_SYS_CTRL_RESET_BBP); - - if (is_mt7612(dev)) - mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); - - mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); - mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); - - mt76x2u_mac_fixup_xtal(dev); - - return 0; -} - -int mt76x2u_mac_start(struct mt76x2_dev *dev) -{ - mt76x2u_mac_reset_counters(dev); - - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - mt76x02_wait_for_wpdma(&dev->mt76, 1000); - usleep_range(50, 100); - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); - - return 0; -} - -int mt76x2u_mac_stop(struct mt76x2_dev *dev) -{ - int i, count = 0, val; - bool stopped = false; - u32 rts_cfg; - - if (test_bit(MT76_REMOVED, &dev->mt76.state)) - return -EIO; - - rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); - mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); - - mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); - mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); - - /* wait tx dma to stop */ - for (i = 0; i < 2000; i++) { - val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); - if (!(val & MT_USB_DMA_CFG_TX_BUSY) && i > 10) - break; - usleep_range(50, 100); - } - - /* page count on TxQ */ - for (i = 0; i < 200; i++) { - if (!(mt76_rr(dev, 0x0438) & 0xffffffff) && - !(mt76_rr(dev, 0x0a30) & 0x000000ff) && - !(mt76_rr(dev, 0x0a34) & 0xff00ff00)) - break; - usleep_range(10, 20); - } - - /* disable tx-rx */ - mt76_clear(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_RX | - MT_MAC_SYS_CTRL_ENABLE_TX); - - /* Wait for MAC to become idle */ - for (i = 0; i < 1000; i++) { - if (!(mt76_rr(dev, MT_MAC_STATUS) & MT_MAC_STATUS_TX) && - !mt76_rr(dev, MT_BBP(IBI, 12))) { - stopped = true; - break; - } - usleep_range(10, 20); - } - - if (!stopped) { - mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); - mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); - - mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); - mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); - } - - /* page count on RxQ */ - for (i = 0; i < 200; i++) { - if (!(mt76_rr(dev, 0x0430) & 0x00ff0000) && - !(mt76_rr(dev, 0x0a30) & 0xffffffff) && - !(mt76_rr(dev, 0x0a34) & 0xffffffff) && - ++count > 10) - break; - msleep(50); - } - - if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 2000)) - dev_warn(dev->mt76.dev, "MAC RX failed to stop\n"); - - /* wait rx dma to stop */ - for (i = 0; i < 2000; i++) { - val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); - if (!(val & MT_USB_DMA_CFG_RX_BUSY) && i > 10) - break; - usleep_range(50, 100); - } - - mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); - - return 0; -} - -void mt76x2u_mac_resume(struct mt76x2_dev *dev) -{ - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); - mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20)); - mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1)); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c deleted file mode 100644 index a80704568780..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2u.h" -#include "mt76x02_util.h" - -static int mt76x2u_start(struct ieee80211_hw *hw) -{ - struct mt76x2_dev *dev = hw->priv; - int ret; - - mutex_lock(&dev->mt76.mutex); - - ret = mt76x2u_mac_start(dev); - if (ret) - goto out; - - set_bit(MT76_STATE_RUNNING, &dev->mt76.state); - -out: - mutex_unlock(&dev->mt76.mutex); - return ret; -} - -static void mt76x2u_stop(struct ieee80211_hw *hw) -{ - struct mt76x2_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); - mt76x2u_stop_hw(dev); - mutex_unlock(&dev->mt76.mutex); -} - -static int mt76x2u_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = hw->priv; - - if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) - mt76x02_mac_setaddr(&dev->mt76, vif->addr); - - mt76x02_vif_init(&dev->mt76, vif, 0); - return 0; -} - -static int -mt76x2u_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef) -{ - int err; - - cancel_delayed_work_sync(&dev->cal_work); - set_bit(MT76_RESET, &dev->mt76.state); - - mt76_set_channel(&dev->mt76); - - mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); - mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); - mt76x2_mac_stop(dev, false); - - err = mt76x2u_phy_set_channel(dev, chandef); - - mt76x2u_mac_resume(dev); - - clear_bit(MT76_RESET, &dev->mt76.state); - mt76_txq_schedule_all(&dev->mt76); - - return err; -} - -static void -mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - struct mt76x2_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - - if (changed & BSS_CHANGED_ASSOC) { - mt76x2u_phy_channel_calibrate(dev); - mt76x2_apply_gain_adj(dev); - } - - if (changed & BSS_CHANGED_BSSID) { - mt76_wr(dev, MT_MAC_BSSID_DW0, - get_unaligned_le32(info->bssid)); - mt76_wr(dev, MT_MAC_BSSID_DW1, - get_unaligned_le16(info->bssid + 4)); - } - - mutex_unlock(&dev->mt76.mutex); -} - -static int -mt76x2u_config(struct ieee80211_hw *hw, u32 changed) -{ - struct mt76x2_dev *dev = hw->priv; - int err = 0; - - mutex_lock(&dev->mt76.mutex); - - 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); - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - err = mt76x2u_set_channel(dev, &hw->conf.chandef); - ieee80211_wake_queues(hw); - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - dev->mt76.txpower_conf = hw->conf.power_level * 2; - - /* convert to per-chain power for 2x2 devices */ - dev->mt76.txpower_conf -= 6; - - if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - mt76x2_phy_set_txpower(dev); - } - - mutex_unlock(&dev->mt76.mutex); - - return err; -} - -static void -mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac) -{ - struct mt76x2_dev *dev = hw->priv; - - set_bit(MT76_SCANNING, &dev->mt76.state); -} - -static void -mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = hw->priv; - - clear_bit(MT76_SCANNING, &dev->mt76.state); -} - -const struct ieee80211_ops mt76x2u_ops = { - .tx = mt76x2_tx, - .start = mt76x2u_start, - .stop = mt76x2u_stop, - .add_interface = mt76x2u_add_interface, - .remove_interface = mt76x02_remove_interface, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, - .set_key = mt76x02_set_key, - .ampdu_action = mt76x02_ampdu_action, - .config = mt76x2u_config, - .wake_tx_queue = mt76_wake_tx_queue, - .bss_info_changed = mt76x2u_bss_info_changed, - .configure_filter = mt76x02_configure_filter, - .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x2u_sw_scan, - .sw_scan_complete = mt76x2u_sw_scan_complete, - .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, -}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c deleted file mode 100644 index fdd94cad7b66..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 - -#include "mt76x2u.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_usb.h" - -#define MT_CMD_HDR_LEN 4 - -#define MCU_FW_URB_MAX_PAYLOAD 0x3900 -#define MCU_ROM_PATCH_MAX_PAYLOAD 2048 - -#define MT76U_MCU_ILM_OFFSET 0x80000 -#define MT76U_MCU_DLM_OFFSET 0x110000 -#define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 - -int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, - bool ext, int rssi, u32 false_cca) -{ - struct { - __le32 channel; - __le32 rssi_val; - __le32 false_cca_val; - } __packed __aligned(4) msg = { - .rssi_val = cpu_to_le32(rssi), - .false_cca_val = cpu_to_le32(false_cca), - }; - struct sk_buff *skb; - u32 val = channel; - - if (ap) - val |= BIT(31); - if (ext) - val |= BIT(30); - msg.channel = cpu_to_le32(val); - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); -} - -static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev) -{ - mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_VENDOR, - 0x12, 0, NULL, 0); -} - -static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev) -{ - struct mt76_usb *usb = &dev->mt76.usb; - const u8 data[] = { - 0x6f, 0xfc, 0x08, 0x01, - 0x20, 0x04, 0x00, 0x00, - 0x00, 0x09, 0x00, - }; - - memcpy(usb->data, data, sizeof(data)); - mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_CLASS, - 0x12, 0, usb->data, sizeof(data)); -} - -static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev) -{ - struct mt76_usb *usb = &dev->mt76.usb; - u8 data[] = { - 0x6f, 0xfc, 0x05, 0x01, - 0x07, 0x01, 0x00, 0x04 - }; - - memcpy(usb->data, data, sizeof(data)); - mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_CLASS, - 0x12, 0, usb->data, sizeof(data)); -} - -static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) -{ - bool rom_protect = !is_mt7612(dev); - struct mt76x02_patch_header *hdr; - u32 val, patch_mask, patch_reg; - const struct firmware *fw; - int err; - - if (rom_protect && - !mt76_poll_msec(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { - dev_err(dev->mt76.dev, - "could not get hardware semaphore for ROM PATCH\n"); - return -ETIMEDOUT; - } - - if (mt76xx_rev(dev) >= MT76XX_REV_E3) { - patch_mask = BIT(0); - patch_reg = MT_MCU_CLOCK_CTL; - } else { - patch_mask = BIT(1); - patch_reg = MT_MCU_COM_REG0; - } - - if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { - dev_info(dev->mt76.dev, "ROM patch already applied\n"); - return 0; - } - - err = request_firmware(&fw, MT7662U_ROM_PATCH, dev->mt76.dev); - if (err < 0) - return err; - - if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { - dev_err(dev->mt76.dev, "failed to load firmware\n"); - err = -EIO; - goto out; - } - - hdr = (struct mt76x02_patch_header *)fw->data; - dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); - - /* enable USB_DMA_CFG */ - val = 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); - mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); - - /* vendor reset */ - mt76x02u_mcu_fw_reset(&dev->mt76); - usleep_range(5000, 10000); - - /* enable FCE to send in-band cmd */ - mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); - /* 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, 0x1); - /* FCE pdma enable */ - mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); - /* FCE skip_fs_en */ - mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); - - err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), - fw->size - sizeof(*hdr), - MCU_ROM_PATCH_MAX_PAYLOAD, - MT76U_MCU_ROM_PATCH_OFFSET); - if (err < 0) { - err = -EIO; - goto out; - } - - mt76x2u_mcu_enable_patch(dev); - mt76x2u_mcu_reset_wmt(dev); - mdelay(20); - - if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 100)) { - dev_err(dev->mt76.dev, "failed to load ROM patch\n"); - err = -ETIMEDOUT; - } - -out: - if (rom_protect) - mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); - release_firmware(fw); - return err; -} - -static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) -{ - u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET; - const struct mt76x02_fw_header *hdr; - int err, len, ilm_len, dlm_len; - const struct firmware *fw; - - err = request_firmware(&fw, MT7662U_FIRMWARE, dev->mt76.dev); - if (err < 0) - return err; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - err = -EINVAL; - goto out; - } - - hdr = (const struct mt76x02_fw_header *)fw->data; - ilm_len = le32_to_cpu(hdr->ilm_len); - dlm_len = le32_to_cpu(hdr->dlm_len); - len = sizeof(*hdr) + ilm_len + dlm_len; - if (fw->size != len) { - err = -EINVAL; - goto out; - } - - 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->build_ver); - dev_info(dev->mt76.dev, "Build: %x\n", val); - dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); - - /* vendor reset */ - mt76x02u_mcu_fw_reset(&dev->mt76); - usleep_range(5000, 10000); - - /* enable USB_DMA_CFG */ - val = 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); - mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); - /* enable FCE to send in-band cmd */ - mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); - /* 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, 0x1); - /* FCE pdma enable */ - mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); - /* FCE skip_fs_en */ - mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); - - /* load ILM */ - err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), - ilm_len, MCU_FW_URB_MAX_PAYLOAD, - MT76U_MCU_ILM_OFFSET); - if (err < 0) { - err = -EIO; - goto out; - } - - /* load DLM */ - if (mt76xx_rev(dev) >= MT76XX_REV_E3) - dlm_offset += 0x800; - err = mt76x02u_mcu_fw_send_data(&dev->mt76, - fw->data + sizeof(*hdr) + ilm_len, - dlm_len, MCU_FW_URB_MAX_PAYLOAD, - dlm_offset); - if (err < 0) { - err = -EIO; - goto out; - } - - mt76x2u_mcu_load_ivb(dev); - if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 100)) { - dev_err(dev->mt76.dev, "firmware failed to start\n"); - err = -ETIMEDOUT; - goto out; - } - - mt76_set(dev, MT_MCU_COM_REG0, BIT(1)); - /* enable FCE to send in-band cmd */ - mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); - dev_dbg(dev->mt76.dev, "firmware running\n"); - mt76x02_set_ethtool_fwver(&dev->mt76, hdr); - -out: - release_firmware(fw); - return err; -} - -int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev) -{ - int err; - - err = mt76x2u_mcu_load_rom_patch(dev); - if (err < 0) - return err; - - return mt76x2u_mcu_load_firmware(dev); -} - -int mt76x2u_mcu_init(struct mt76x2_dev *dev) -{ - int err; - - err = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, - 1, false); - if (err < 0) - return err; - - return mt76x02_mcu_set_radio_state(&dev->mt76, true, false); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c deleted file mode 100644 index 06362d3487be..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * 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 "mt76x2u.h" -#include "mt76x2_eeprom.h" - -void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - bool is_5ghz = chan->band == NL80211_BAND_5GHZ; - - if (mt76x2_channel_silent(dev)) - return; - - mt76x2u_mac_stop(dev); - - if (is_5ghz) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, false); - - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, false); - - mt76x2u_mac_resume(dev); -} - -static void -mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) -{ - u8 channel = dev->mt76.chandef.chan->hw_value; - int freq, freq1; - u32 false_cca; - - freq = dev->mt76.chandef.chan->center_freq; - freq1 = dev->mt76.chandef.center_freq1; - - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_80: { - int ch_group_index; - - ch_group_index = (freq - freq1 + 30) / 20; - if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) - ch_group_index = 0; - channel += 6 - ch_group_index * 4; - break; - } - case NL80211_CHAN_WIDTH_40: - if (freq1 > freq) - channel += 2; - else - channel -= 2; - break; - default: - break; - } - - dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); - false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, - mt76_rr(dev, MT_RX_STAT_1)); - - mt76x2u_mcu_set_dynamic_vga(dev, channel, false, false, - dev->cal.avg_rssi_all, false_cca); -} - -void mt76x2u_phy_calibrate(struct work_struct *work) -{ - struct mt76x2_dev *dev; - - dev = container_of(work, struct mt76x2_dev, cal_work.work); - mt76x2_phy_tssi_compensate(dev, false); - mt76x2u_phy_update_channel_gain(dev); - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, - MT_CALIBRATE_INTERVAL); -} - -int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef) -{ - u32 ext_cca_chan[4] = { - [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(0)), - [1] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(1)), - [2] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(2)), - [3] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 3) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 2) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | - FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(3)), - }; - bool scan = test_bit(MT76_SCANNING, &dev->mt76.state); - struct ieee80211_channel *chan = chandef->chan; - u8 channel = chan->hw_value, bw, bw_index; - int ch_group_index, freq, freq1, ret; - - dev->cal.channel_cal_done = false; - freq = chandef->chan->center_freq; - freq1 = chandef->center_freq1; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_40: - bw = 1; - if (freq1 > freq) { - bw_index = 1; - ch_group_index = 0; - } else { - bw_index = 3; - ch_group_index = 1; - } - channel += 2 - ch_group_index * 4; - break; - case NL80211_CHAN_WIDTH_80: - ch_group_index = (freq - freq1 + 30) / 20; - if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) - ch_group_index = 0; - bw = 2; - bw_index = ch_group_index; - channel += 6 - ch_group_index * 4; - break; - default: - bw = 0; - bw_index = 0; - ch_group_index = 0; - break; - } - - mt76x2_read_rx_gain(dev); - mt76x2_phy_set_txpower_regs(dev, chan->band); - mt76x2_configure_tx_delay(dev, chan->band, bw); - mt76x2_phy_set_txpower(dev); - - mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); - mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); - - mt76_rmw(dev, MT_EXT_CCA_CFG, - (MT_EXT_CCA_CFG_CCA0 | - MT_EXT_CCA_CFG_CCA1 | - MT_EXT_CCA_CFG_CCA2 | - MT_EXT_CCA_CFG_CCA3 | - MT_EXT_CCA_CFG_CCA_MASK), - ext_cca_chan[ch_group_index]); - - ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); - if (ret) - return ret; - - mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); - - /* Enable LDPC Rx */ - if (mt76xx_rev(dev) >= MT76XX_REV_E3) - mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); - - if (!dev->cal.init_cal_done) { - u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); - - if (val != 0xff) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, - 0, false); - } - - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, false); - - /* Rx LPF calibration */ - if (!dev->cal.init_cal_done) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, false); - dev->cal.init_cal_done = true; - - mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2); - mt76_wr(dev, MT_BBP(AGC, 7), 0x08081010); - mt76_wr(dev, MT_BBP(AGC, 11), 0x00000404); - mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); - mt76_wr(dev, MT_TXOP_CTRL_CFG, 0X04101b3f); - - mt76_set(dev, MT_BBP(TXO, 4), BIT(25)); - mt76_set(dev, MT_BBP(RXO, 13), BIT(8)); - - if (scan) - return 0; - - if (mt76x02_tssi_enabled(&dev->mt76)) { - /* init default values for temp compensation */ - mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, - 0x38); - mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, - 0x38); - - /* init tssi calibration */ - if (!mt76x2_channel_silent(dev)) { - struct ieee80211_channel *chan; - u32 flag = 0; - - chan = dev->mt76.chandef.chan; - if (chan->band == NL80211_BAND_5GHZ) - flag |= BIT(0); - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) - flag |= BIT(8); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, - flag, false); - dev->cal.tssi_cal_done = true; - } - } - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, - MT_CALIBRATE_INTERVAL); - return 0; -} -- cgit