├── .gitignore ├── Makefile ├── agg-rx.c ├── debugfs.c ├── dma.c ├── dma.h ├── eeprom.c ├── firmware ├── LICENSE ├── WIFI_MT7961_patch_mcu_1_2_hdr.bin ├── WIFI_RAM_CODE_MT7961_1.bin ├── mt7603_e1.bin ├── mt7603_e2.bin ├── mt7610e.bin ├── mt7615_cr4.bin ├── mt7615_n9.bin ├── mt7615_rom_patch.bin ├── mt7622_n9.bin ├── mt7622_rom_patch.bin ├── mt7628_e1.bin ├── mt7628_e2.bin ├── mt7662.bin ├── mt7662_firmware_e3_v1.7.bin ├── mt7662_firmware_e3_v1.9.bin ├── mt7662_patch_e3_hdr_v0.0.2_P69.bin ├── mt7662_rom_patch.bin ├── mt7663_n9_rebb.bin ├── mt7663_n9_v3.bin ├── mt7663pr2h.bin ├── mt7663pr2h_rebb.bin ├── mt7915_rom_patch.bin ├── mt7915_wa.bin └── mt7915_wm.bin ├── mac80211.c ├── mcu.c ├── mmio.c ├── mt76.h ├── mt7603 ├── Makefile ├── beacon.c ├── core.c ├── debugfs.c ├── dma.c ├── eeprom.c ├── eeprom.h ├── init.c ├── mac.c ├── mac.h ├── main.c ├── mcu.c ├── mcu.h ├── mt7603.h ├── pci.c ├── regs.h └── soc.c ├── mt7615 ├── Kconfig ├── Makefile ├── debugfs.c ├── dma.c ├── eeprom.c ├── eeprom.h ├── init.c ├── mac.c ├── mac.h ├── main.c ├── mcu.c ├── mcu.h ├── mmio.c ├── mt7615.h ├── mt7615_trace.h ├── pci.c ├── pci_init.c ├── pci_mac.c ├── regs.h ├── sdio.c ├── sdio_mcu.c ├── soc.c ├── testmode.c ├── trace.c ├── usb.c ├── usb_mcu.c └── usb_sdio.c ├── mt76_connac.h ├── mt76_connac_mac.c ├── mt76_connac_mcu.c ├── mt76_connac_mcu.h ├── mt76x0 ├── Makefile ├── eeprom.c ├── eeprom.h ├── init.c ├── initvals.h ├── initvals_init.h ├── initvals_phy.h ├── main.c ├── mcu.h ├── mt76x0.h ├── pci.c ├── pci_mcu.c ├── phy.c ├── phy.h ├── usb.c └── usb_mcu.c ├── mt76x02.h ├── mt76x02_beacon.c ├── mt76x02_debugfs.c ├── mt76x02_dfs.c ├── mt76x02_dfs.h ├── mt76x02_dma.h ├── mt76x02_eeprom.c ├── mt76x02_eeprom.h ├── mt76x02_mac.c ├── mt76x02_mac.h ├── mt76x02_mcu.c ├── mt76x02_mcu.h ├── mt76x02_mmio.c ├── mt76x02_phy.c ├── mt76x02_phy.h ├── mt76x02_regs.h ├── mt76x02_trace.c ├── mt76x02_trace.h ├── mt76x02_txrx.c ├── mt76x02_usb.h ├── mt76x02_usb_core.c ├── mt76x02_usb_mcu.c ├── mt76x02_util.c ├── mt76x2 ├── Makefile ├── debugfs.c ├── eeprom.c ├── eeprom.h ├── init.c ├── mac.c ├── mac.h ├── mcu.c ├── mcu.h ├── mt76x2.h ├── mt76x2u.h ├── pci.c ├── pci_init.c ├── pci_main.c ├── pci_mcu.c ├── pci_phy.c ├── phy.c ├── usb.c ├── usb_init.c ├── usb_mac.c ├── usb_main.c ├── usb_mcu.c └── usb_phy.c ├── mt7915 ├── Kconfig ├── Makefile ├── debugfs.c ├── dma.c ├── eeprom.c ├── eeprom.h ├── init.c ├── mac.c ├── mac.h ├── main.c ├── mcu.c ├── mcu.h ├── mmio.c ├── mt7915.h ├── pci.c ├── regs.h ├── testmode.c └── testmode.h ├── mt7921 ├── Kconfig ├── Makefile ├── debugfs.c ├── dma.c ├── eeprom.h ├── init.c ├── mac.c ├── mac.h ├── main.c ├── mcu.c ├── mcu.h ├── mt7921.h ├── mt7921_trace.h ├── pci.c ├── pci_mac.c ├── pci_mcu.c ├── regs.h ├── sdio.c ├── sdio_mac.c ├── sdio_mcu.c ├── testmode.c └── trace.c ├── pci.c ├── scripts └── single-sku.pl ├── sdio.c ├── sdio.h ├── sdio_txrx.c ├── testmode.c ├── testmode.h ├── tools ├── CMakeLists.txt ├── README.md ├── eeprom.c ├── fields.c ├── main.c └── mt76-test.h ├── trace.c ├── trace.h ├── tx.c ├── usb.c ├── usb_trace.c ├── usb_trace.h ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.o 3 | *.ko 4 | *.mod 5 | *.mod.c 6 | *.symvers 7 | *.symvers.tmp 8 | modules.order 9 | ipkg-* 10 | CMakeFiles 11 | CMakeCache.txt 12 | cmake_install.cmake 13 | tools/Makefile 14 | tools/mt76-test 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | EXTRA_CFLAGS += -Werror -DCONFIG_MT76_LEDS 3 | obj-m := mt76.o 4 | obj-$(CONFIG_MT76_USB) += mt76-usb.o 5 | obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o 6 | obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o 7 | obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o 8 | obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o 9 | 10 | mt76-y := \ 11 | mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ 12 | tx.o agg-rx.o mcu.o 13 | 14 | mt76-$(CONFIG_PCI) += pci.o 15 | mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o 16 | 17 | mt76-usb-y := usb.o usb_trace.o 18 | mt76-sdio-y := sdio.o sdio_txrx.o 19 | 20 | CFLAGS_trace.o := -I$(src) 21 | CFLAGS_usb_trace.o := -I$(src) 22 | CFLAGS_mt76x02_trace.o := -I$(src) 23 | 24 | mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ 25 | mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \ 26 | mt76x02_txrx.o mt76x02_trace.o mt76x02_debugfs.o \ 27 | mt76x02_dfs.o mt76x02_beacon.o 28 | 29 | mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o 30 | 31 | mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o 32 | 33 | obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ 34 | obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ 35 | obj-$(CONFIG_MT7603E) += mt7603/ 36 | obj-$(CONFIG_MT7615_COMMON) += mt7615/ 37 | obj-$(CONFIG_MT7915E) += mt7915/ 38 | obj-$(CONFIG_MT7921E) += mt7921/ 39 | -------------------------------------------------------------------------------- /debugfs.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | #include "mt76.h" 6 | 7 | static int 8 | mt76_reg_set(void *data, u64 val) 9 | { 10 | struct mt76_dev *dev = data; 11 | 12 | __mt76_wr(dev, dev->debugfs_reg, val); 13 | return 0; 14 | } 15 | 16 | static int 17 | mt76_reg_get(void *data, u64 *val) 18 | { 19 | struct mt76_dev *dev = data; 20 | 21 | *val = __mt76_rr(dev, dev->debugfs_reg); 22 | return 0; 23 | } 24 | 25 | DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, 26 | "0x%08llx\n"); 27 | 28 | int mt76_queues_read(struct seq_file *s, void *data) 29 | { 30 | struct mt76_dev *dev = dev_get_drvdata(s->private); 31 | int i; 32 | 33 | seq_puts(s, " queue | hw-queued | head | tail |\n"); 34 | for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) { 35 | struct mt76_queue *q = dev->phy.q_tx[i]; 36 | 37 | if (!q) 38 | continue; 39 | 40 | seq_printf(s, " %9d | %9d | %9d | %9d |\n", 41 | i, q->queued, q->head, q->tail); 42 | } 43 | 44 | return 0; 45 | } 46 | EXPORT_SYMBOL_GPL(mt76_queues_read); 47 | 48 | static int mt76_rx_queues_read(struct seq_file *s, void *data) 49 | { 50 | struct mt76_dev *dev = dev_get_drvdata(s->private); 51 | int i, queued; 52 | 53 | seq_puts(s, " queue | hw-queued | head | tail |\n"); 54 | mt76_for_each_q_rx(dev, i) { 55 | struct mt76_queue *q = &dev->q_rx[i]; 56 | 57 | queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; 58 | seq_printf(s, " %9d | %9d | %9d | %9d |\n", 59 | i, queued, q->head, q->tail); 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | void mt76_seq_puts_array(struct seq_file *file, const char *str, 66 | s8 *val, int len) 67 | { 68 | int i; 69 | 70 | seq_printf(file, "%10s:", str); 71 | for (i = 0; i < len; i++) 72 | seq_printf(file, " %2d", val[i]); 73 | seq_puts(file, "\n"); 74 | } 75 | EXPORT_SYMBOL_GPL(mt76_seq_puts_array); 76 | 77 | static int mt76_read_rate_txpower(struct seq_file *s, void *data) 78 | { 79 | struct mt76_dev *dev = dev_get_drvdata(s->private); 80 | 81 | mt76_seq_puts_array(s, "CCK", dev->rate_power.cck, 82 | ARRAY_SIZE(dev->rate_power.cck)); 83 | mt76_seq_puts_array(s, "OFDM", dev->rate_power.ofdm, 84 | ARRAY_SIZE(dev->rate_power.ofdm)); 85 | mt76_seq_puts_array(s, "STBC", dev->rate_power.stbc, 86 | ARRAY_SIZE(dev->rate_power.stbc)); 87 | mt76_seq_puts_array(s, "HT", dev->rate_power.ht, 88 | ARRAY_SIZE(dev->rate_power.ht)); 89 | mt76_seq_puts_array(s, "VHT", dev->rate_power.vht, 90 | ARRAY_SIZE(dev->rate_power.vht)); 91 | return 0; 92 | } 93 | 94 | struct dentry * 95 | mt76_register_debugfs_fops(struct mt76_phy *phy, 96 | const struct file_operations *ops) 97 | { 98 | const struct file_operations *fops = ops ? ops : &fops_regval; 99 | struct mt76_dev *dev = phy->dev; 100 | struct dentry *dir; 101 | 102 | dir = debugfs_create_dir("mt76", phy->hw->wiphy->debugfsdir); 103 | if (!dir) 104 | return NULL; 105 | 106 | debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin); 107 | debugfs_create_bool("led_active_low", 0600, dir, &dev->led_al); 108 | debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); 109 | debugfs_create_file_unsafe("regval", 0600, dir, dev, fops); 110 | debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); 111 | if (dev->otp.data) 112 | debugfs_create_blob("otp", 0400, dir, &dev->otp); 113 | debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, 114 | mt76_read_rate_txpower); 115 | debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir, 116 | mt76_rx_queues_read); 117 | 118 | return dir; 119 | } 120 | EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops); 121 | -------------------------------------------------------------------------------- /dma.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | #ifndef __MT76_DMA_H 6 | #define __MT76_DMA_H 7 | 8 | #define DMA_DUMMY_DATA ((void *)~0) 9 | 10 | #define MT_RING_SIZE 0x10 11 | 12 | #define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0) 13 | #define MT_DMA_CTL_LAST_SEC1 BIT(14) 14 | #define MT_DMA_CTL_BURST BIT(15) 15 | #define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16) 16 | #define MT_DMA_CTL_LAST_SEC0 BIT(30) 17 | #define MT_DMA_CTL_DMA_DONE BIT(31) 18 | 19 | #define MT_DMA_HDR_LEN 4 20 | #define MT_RX_INFO_LEN 4 21 | #define MT_FCE_INFO_LEN 4 22 | #define MT_RX_RXWI_LEN 32 23 | 24 | struct mt76_desc { 25 | __le32 buf0; 26 | __le32 ctrl; 27 | __le32 buf1; 28 | __le32 info; 29 | } __packed __aligned(4); 30 | 31 | enum mt76_qsel { 32 | MT_QSEL_MGMT, 33 | MT_QSEL_HCCA, 34 | MT_QSEL_EDCA, 35 | MT_QSEL_EDCA_2, 36 | }; 37 | 38 | enum mt76_mcu_evt_type { 39 | EVT_CMD_DONE, 40 | EVT_CMD_ERROR, 41 | EVT_CMD_RETRY, 42 | EVT_EVENT_PWR_RSP, 43 | EVT_EVENT_WOW_RSP, 44 | EVT_EVENT_CARRIER_DETECT_RSP, 45 | EVT_EVENT_DFS_DETECT_RSP, 46 | }; 47 | 48 | int mt76_dma_rx_poll(struct napi_struct *napi, int budget); 49 | void mt76_dma_attach(struct mt76_dev *dev); 50 | void mt76_dma_cleanup(struct mt76_dev *dev); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /firmware/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Ralink, A MediaTek Company 2 | All rights reserved. 3 | 4 | Redistribution. Redistribution and use in binary form, without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions must reproduce the above copyright notice and the 9 | following disclaimer in the documentation and/or other materials 10 | provided with the distribution. 11 | * Neither the name of Ralink Technology Corporation nor the names of its 12 | suppliers may be used to endorse or promote products derived from this 13 | software without specific prior written permission. 14 | * No reverse engineering, decompilation, or disassembly of this software 15 | is permitted. 16 | 17 | Limited patent license. Ralink Technology Corporation grants a world-wide, 18 | royalty-free, non-exclusive license under patents it now or hereafter 19 | owns or controls to make, have made, use, import, offer to sell and 20 | sell ("Utilize") this software, but solely to the extent that any 21 | such patent is necessary to Utilize the software alone, or in 22 | combination with an operating system licensed under an approved Open 23 | Source license as listed by the Open Source Initiative at 24 | http://opensource.org/licenses. The patent license shall not apply to 25 | any other combinations which include this software. No hardware per 26 | se is licensed hereunder. 27 | 28 | DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 29 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 30 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 32 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 33 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 34 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 35 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 37 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 38 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 39 | DAMAGE. 40 | -------------------------------------------------------------------------------- /firmware/WIFI_MT7961_patch_mcu_1_2_hdr.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/WIFI_MT7961_patch_mcu_1_2_hdr.bin -------------------------------------------------------------------------------- /firmware/WIFI_RAM_CODE_MT7961_1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/WIFI_RAM_CODE_MT7961_1.bin -------------------------------------------------------------------------------- /firmware/mt7603_e1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7603_e1.bin -------------------------------------------------------------------------------- /firmware/mt7603_e2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7603_e2.bin -------------------------------------------------------------------------------- /firmware/mt7610e.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7610e.bin -------------------------------------------------------------------------------- /firmware/mt7615_cr4.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7615_cr4.bin -------------------------------------------------------------------------------- /firmware/mt7615_n9.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7615_n9.bin -------------------------------------------------------------------------------- /firmware/mt7615_rom_patch.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7615_rom_patch.bin -------------------------------------------------------------------------------- /firmware/mt7622_n9.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7622_n9.bin -------------------------------------------------------------------------------- /firmware/mt7622_rom_patch.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7622_rom_patch.bin -------------------------------------------------------------------------------- /firmware/mt7628_e1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7628_e1.bin -------------------------------------------------------------------------------- /firmware/mt7628_e2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7628_e2.bin -------------------------------------------------------------------------------- /firmware/mt7662.bin: -------------------------------------------------------------------------------- 1 | mt7662_firmware_e3_v1.9.bin -------------------------------------------------------------------------------- /firmware/mt7662_firmware_e3_v1.7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7662_firmware_e3_v1.7.bin -------------------------------------------------------------------------------- /firmware/mt7662_firmware_e3_v1.9.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7662_firmware_e3_v1.9.bin -------------------------------------------------------------------------------- /firmware/mt7662_patch_e3_hdr_v0.0.2_P69.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7662_patch_e3_hdr_v0.0.2_P69.bin -------------------------------------------------------------------------------- /firmware/mt7662_rom_patch.bin: -------------------------------------------------------------------------------- 1 | mt7662_patch_e3_hdr_v0.0.2_P69.bin -------------------------------------------------------------------------------- /firmware/mt7663_n9_rebb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7663_n9_rebb.bin -------------------------------------------------------------------------------- /firmware/mt7663_n9_v3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7663_n9_v3.bin -------------------------------------------------------------------------------- /firmware/mt7663pr2h.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7663pr2h.bin -------------------------------------------------------------------------------- /firmware/mt7663pr2h_rebb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7663pr2h_rebb.bin -------------------------------------------------------------------------------- /firmware/mt7915_rom_patch.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7915_rom_patch.bin -------------------------------------------------------------------------------- /firmware/mt7915_wa.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7915_wa.bin -------------------------------------------------------------------------------- /firmware/mt7915_wm.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LorenzoBianconi/mt76/26fb105e538c0b90ca69525adb5b20d016993e7a/firmware/mt7915_wm.bin -------------------------------------------------------------------------------- /mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2019 Lorenzo Bianconi 4 | */ 5 | 6 | #include "mt76.h" 7 | 8 | struct sk_buff * 9 | mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, 10 | int data_len) 11 | { 12 | const struct mt76_mcu_ops *ops = dev->mcu_ops; 13 | int length = ops->headroom + data_len + ops->tailroom; 14 | struct sk_buff *skb; 15 | 16 | skb = alloc_skb(length, GFP_KERNEL); 17 | if (!skb) 18 | return NULL; 19 | 20 | memset(skb->head, 0, length); 21 | skb_reserve(skb, ops->headroom); 22 | 23 | if (data && data_len) 24 | skb_put_data(skb, data, data_len); 25 | 26 | return skb; 27 | } 28 | EXPORT_SYMBOL_GPL(mt76_mcu_msg_alloc); 29 | 30 | struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, 31 | unsigned long expires) 32 | { 33 | unsigned long timeout; 34 | 35 | if (!time_is_after_jiffies(expires)) 36 | return NULL; 37 | 38 | timeout = expires - jiffies; 39 | wait_event_timeout(dev->mcu.wait, 40 | (!skb_queue_empty(&dev->mcu.res_q) || 41 | test_bit(MT76_MCU_RESET, &dev->phy.state)), 42 | timeout); 43 | return skb_dequeue(&dev->mcu.res_q); 44 | } 45 | EXPORT_SYMBOL_GPL(mt76_mcu_get_response); 46 | 47 | void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb) 48 | { 49 | skb_queue_tail(&dev->mcu.res_q, skb); 50 | wake_up(&dev->mcu.wait); 51 | } 52 | EXPORT_SYMBOL_GPL(mt76_mcu_rx_event); 53 | 54 | int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data, 55 | int len, bool wait_resp, struct sk_buff **ret_skb) 56 | { 57 | struct sk_buff *skb; 58 | 59 | if (dev->mcu_ops->mcu_send_msg) 60 | return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp); 61 | 62 | skb = mt76_mcu_msg_alloc(dev, data, len); 63 | if (!skb) 64 | return -ENOMEM; 65 | 66 | return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb); 67 | } 68 | EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg); 69 | 70 | int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, 71 | int cmd, bool wait_resp, 72 | struct sk_buff **ret_skb) 73 | { 74 | unsigned long expires; 75 | int ret, seq; 76 | 77 | if (ret_skb) 78 | *ret_skb = NULL; 79 | 80 | mutex_lock(&dev->mcu.mutex); 81 | 82 | ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); 83 | if (ret < 0) 84 | goto out; 85 | 86 | if (!wait_resp) { 87 | ret = 0; 88 | goto out; 89 | } 90 | 91 | expires = jiffies + dev->mcu.timeout; 92 | 93 | do { 94 | skb = mt76_mcu_get_response(dev, expires); 95 | ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq); 96 | if (!ret && ret_skb) 97 | *ret_skb = skb; 98 | else 99 | dev_kfree_skb(skb); 100 | } while (ret == -EAGAIN); 101 | 102 | out: 103 | mutex_unlock(&dev->mcu.mutex); 104 | 105 | return ret; 106 | } 107 | EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg); 108 | 109 | int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, 110 | int len, int max_len) 111 | { 112 | int err, cur_len; 113 | 114 | while (len > 0) { 115 | cur_len = min_t(int, max_len, len); 116 | 117 | err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false); 118 | if (err) 119 | return err; 120 | 121 | data += cur_len; 122 | len -= cur_len; 123 | 124 | if (dev->queue_ops->tx_cleanup) 125 | dev->queue_ops->tx_cleanup(dev, 126 | dev->q_mcu[MT_MCUQ_FWDL], 127 | false); 128 | } 129 | 130 | return 0; 131 | } 132 | EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware); 133 | -------------------------------------------------------------------------------- /mmio.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include "mt76.h" 7 | #include "trace.h" 8 | 9 | static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) 10 | { 11 | u32 val; 12 | 13 | val = readl(dev->mmio.regs + offset); 14 | trace_reg_rr(dev, offset, val); 15 | 16 | return val; 17 | } 18 | 19 | static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val) 20 | { 21 | trace_reg_wr(dev, offset, val); 22 | writel(val, dev->mmio.regs + offset); 23 | } 24 | 25 | static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) 26 | { 27 | val |= mt76_mmio_rr(dev, offset) & ~mask; 28 | mt76_mmio_wr(dev, offset, val); 29 | return val; 30 | } 31 | 32 | static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset, 33 | const void *data, int len) 34 | { 35 | __iowrite32_copy(dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4)); 36 | } 37 | 38 | static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset, 39 | void *data, int len) 40 | { 41 | __ioread32_copy(data, dev->mmio.regs + offset, DIV_ROUND_UP(len, 4)); 42 | } 43 | 44 | static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base, 45 | const struct mt76_reg_pair *data, int len) 46 | { 47 | while (len > 0) { 48 | mt76_mmio_wr(dev, data->reg, data->value); 49 | data++; 50 | len--; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base, 57 | struct mt76_reg_pair *data, int len) 58 | { 59 | while (len > 0) { 60 | data->value = mt76_mmio_rr(dev, data->reg); 61 | data++; 62 | len--; 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, 69 | u32 clear, u32 set) 70 | { 71 | unsigned long flags; 72 | 73 | spin_lock_irqsave(&dev->mmio.irq_lock, flags); 74 | dev->mmio.irqmask &= ~clear; 75 | dev->mmio.irqmask |= set; 76 | if (addr) 77 | mt76_mmio_wr(dev, addr, dev->mmio.irqmask); 78 | spin_unlock_irqrestore(&dev->mmio.irq_lock, flags); 79 | } 80 | EXPORT_SYMBOL_GPL(mt76_set_irq_mask); 81 | 82 | void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) 83 | { 84 | static const struct mt76_bus_ops mt76_mmio_ops = { 85 | .rr = mt76_mmio_rr, 86 | .rmw = mt76_mmio_rmw, 87 | .wr = mt76_mmio_wr, 88 | .write_copy = mt76_mmio_write_copy, 89 | .read_copy = mt76_mmio_read_copy, 90 | .wr_rp = mt76_mmio_wr_rp, 91 | .rd_rp = mt76_mmio_rd_rp, 92 | .type = MT76_BUS_MMIO, 93 | }; 94 | 95 | dev->bus = &mt76_mmio_ops; 96 | dev->mmio.regs = regs; 97 | 98 | spin_lock_init(&dev->mmio.irq_lock); 99 | } 100 | EXPORT_SYMBOL_GPL(mt76_mmio_init); 101 | -------------------------------------------------------------------------------- /mt7603/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | EXTRA_CFLAGS += -Werror -DCONFIG_MT76_LEDS 3 | obj-m += mt7603e.o 4 | 5 | mt7603e-y := \ 6 | pci.o soc.o main.o init.o mcu.o \ 7 | core.o dma.o mac.o eeprom.o \ 8 | beacon.o debugfs.o 9 | -------------------------------------------------------------------------------- /mt7603/core.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include "mt7603.h" 4 | #include "../trace.h" 5 | 6 | void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) 7 | { 8 | struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 9 | 10 | mt7603_irq_enable(dev, MT_INT_RX_DONE(q)); 11 | } 12 | 13 | irqreturn_t mt7603_irq_handler(int irq, void *dev_instance) 14 | { 15 | struct mt7603_dev *dev = dev_instance; 16 | u32 intr; 17 | 18 | intr = mt76_rr(dev, MT_INT_SOURCE_CSR); 19 | mt76_wr(dev, MT_INT_SOURCE_CSR, intr); 20 | 21 | if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) 22 | return IRQ_NONE; 23 | 24 | trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); 25 | 26 | intr &= dev->mt76.mmio.irqmask; 27 | 28 | if (intr & MT_INT_MAC_IRQ3) { 29 | u32 hwintr = mt76_rr(dev, MT_HW_INT_STATUS(3)); 30 | 31 | mt76_wr(dev, MT_HW_INT_STATUS(3), hwintr); 32 | if (hwintr & MT_HW_INT3_PRE_TBTT0) 33 | tasklet_schedule(&dev->mt76.pre_tbtt_tasklet); 34 | 35 | if ((hwintr & MT_HW_INT3_TBTT0) && dev->mt76.csa_complete) 36 | mt76_csa_finish(&dev->mt76); 37 | } 38 | 39 | if (intr & MT_INT_TX_DONE_ALL) { 40 | mt7603_irq_disable(dev, MT_INT_TX_DONE_ALL); 41 | napi_schedule(&dev->mt76.tx_napi); 42 | } 43 | 44 | if (intr & MT_INT_RX_DONE(0)) { 45 | mt7603_irq_disable(dev, MT_INT_RX_DONE(0)); 46 | napi_schedule(&dev->mt76.napi[0]); 47 | } 48 | 49 | if (intr & MT_INT_RX_DONE(1)) { 50 | mt7603_irq_disable(dev, MT_INT_RX_DONE(1)); 51 | napi_schedule(&dev->mt76.napi[1]); 52 | } 53 | 54 | return IRQ_HANDLED; 55 | } 56 | 57 | u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr) 58 | { 59 | u32 base = addr & MT_MCU_PCIE_REMAP_2_BASE; 60 | u32 offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET; 61 | 62 | dev->bus_ops->wr(&dev->mt76, MT_MCU_PCIE_REMAP_2, base); 63 | 64 | return MT_PCIE_REMAP_BASE_2 + offset; 65 | } 66 | -------------------------------------------------------------------------------- /mt7603/debugfs.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include "mt7603.h" 4 | 5 | static int 6 | mt7603_reset_read(struct seq_file *s, void *data) 7 | { 8 | struct mt7603_dev *dev = dev_get_drvdata(s->private); 9 | static const char * const reset_cause_str[] = { 10 | [RESET_CAUSE_TX_HANG] = "TX hang", 11 | [RESET_CAUSE_TX_BUSY] = "TX DMA busy stuck", 12 | [RESET_CAUSE_RX_BUSY] = "RX DMA busy stuck", 13 | [RESET_CAUSE_RX_PSE_BUSY] = "RX PSE busy stuck", 14 | [RESET_CAUSE_BEACON_STUCK] = "Beacon stuck", 15 | [RESET_CAUSE_MCU_HANG] = "MCU hang", 16 | [RESET_CAUSE_RESET_FAILED] = "PSE reset failed", 17 | }; 18 | int i; 19 | 20 | for (i = 0; i < ARRAY_SIZE(reset_cause_str); i++) { 21 | if (!reset_cause_str[i]) 22 | continue; 23 | 24 | seq_printf(s, "%20s: %u\n", reset_cause_str[i], 25 | dev->reset_cause[i]); 26 | } 27 | 28 | return 0; 29 | } 30 | 31 | static int 32 | mt7603_radio_read(struct seq_file *s, void *data) 33 | { 34 | struct mt7603_dev *dev = dev_get_drvdata(s->private); 35 | 36 | seq_printf(s, "Sensitivity: %d\n", dev->sensitivity); 37 | seq_printf(s, "False CCA: ofdm=%d cck=%d\n", 38 | dev->false_cca_ofdm, dev->false_cca_cck); 39 | 40 | return 0; 41 | } 42 | 43 | static int 44 | mt7603_edcca_set(void *data, u64 val) 45 | { 46 | struct mt7603_dev *dev = data; 47 | 48 | mutex_lock(&dev->mt76.mutex); 49 | 50 | dev->ed_monitor_enabled = !!val; 51 | dev->ed_monitor = dev->ed_monitor_enabled && 52 | dev->mt76.region == NL80211_DFS_ETSI; 53 | mt7603_init_edcca(dev); 54 | 55 | mutex_unlock(&dev->mt76.mutex); 56 | 57 | return 0; 58 | } 59 | 60 | static int 61 | mt7603_edcca_get(void *data, u64 *val) 62 | { 63 | struct mt7603_dev *dev = data; 64 | 65 | *val = dev->ed_monitor_enabled; 66 | return 0; 67 | } 68 | 69 | DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get, 70 | mt7603_edcca_set, "%lld\n"); 71 | 72 | static int 73 | mt7603_ampdu_stat_show(struct seq_file *file, void *data) 74 | { 75 | struct mt7603_dev *dev = file->private; 76 | int bound[3], i, range; 77 | 78 | range = mt76_rr(dev, MT_AGG_ASRCR); 79 | for (i = 0; i < ARRAY_SIZE(bound); i++) 80 | bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; 81 | 82 | seq_printf(file, "Length: %8d | ", bound[0]); 83 | for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 84 | seq_printf(file, "%3d -%3d | ", 85 | bound[i], bound[i + 1]); 86 | seq_puts(file, "\nCount: "); 87 | for (i = 0; i < ARRAY_SIZE(bound); i++) 88 | seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); 89 | seq_puts(file, "\n"); 90 | 91 | return 0; 92 | } 93 | 94 | DEFINE_SHOW_ATTRIBUTE(mt7603_ampdu_stat); 95 | 96 | void mt7603_init_debugfs(struct mt7603_dev *dev) 97 | { 98 | struct dentry *dir; 99 | 100 | dir = mt76_register_debugfs(&dev->mt76); 101 | if (!dir) 102 | return; 103 | 104 | debugfs_create_file("ampdu_stat", 0400, dir, dev, 105 | &mt7603_ampdu_stat_fops); 106 | debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, 107 | mt76_queues_read); 108 | debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); 109 | debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test); 110 | debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir, 111 | mt7603_reset_read); 112 | debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, 113 | mt7603_radio_read); 114 | debugfs_create_u8("sensitivity_limit", 0600, dir, 115 | &dev->sensitivity_limit); 116 | debugfs_create_bool("dynamic_sensitivity", 0600, dir, 117 | &dev->dynamic_sensitivity); 118 | } 119 | -------------------------------------------------------------------------------- /mt7603/eeprom.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include 4 | #include "mt7603.h" 5 | #include "eeprom.h" 6 | 7 | static int 8 | mt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data) 9 | { 10 | u32 val; 11 | int i; 12 | 13 | val = mt76_rr(dev, base + MT_EFUSE_CTRL); 14 | val &= ~(MT_EFUSE_CTRL_AIN | 15 | MT_EFUSE_CTRL_MODE); 16 | val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); 17 | val |= MT_EFUSE_CTRL_KICK; 18 | mt76_wr(dev, base + MT_EFUSE_CTRL, val); 19 | 20 | if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 21 | return -ETIMEDOUT; 22 | 23 | udelay(2); 24 | 25 | val = mt76_rr(dev, base + MT_EFUSE_CTRL); 26 | if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT || 27 | WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) { 28 | memset(data, 0xff, 16); 29 | return 0; 30 | } 31 | 32 | for (i = 0; i < 4; i++) { 33 | val = mt76_rr(dev, base + MT_EFUSE_RDATA(i)); 34 | put_unaligned_le32(val, data + 4 * i); 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | static int 41 | mt7603_efuse_init(struct mt7603_dev *dev) 42 | { 43 | u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE); 44 | int len = MT7603_EEPROM_SIZE; 45 | void *buf; 46 | int ret, i; 47 | 48 | if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY) 49 | return 0; 50 | 51 | dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL); 52 | dev->mt76.otp.size = len; 53 | if (!dev->mt76.otp.data) 54 | return -ENOMEM; 55 | 56 | buf = dev->mt76.otp.data; 57 | for (i = 0; i + 16 <= len; i += 16) { 58 | ret = mt7603_efuse_read(dev, base, i, buf + i); 59 | if (ret) 60 | return ret; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | static bool 67 | mt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse) 68 | { 69 | if (!efuse[MT_EE_TEMP_SENSOR_CAL]) 70 | return false; 71 | 72 | if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0) 73 | return false; 74 | 75 | if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0) 76 | return false; 77 | 78 | if (!efuse[MT_EE_CP_FT_VERSION]) 79 | return false; 80 | 81 | if (!efuse[MT_EE_XTAL_FREQ_OFFSET]) 82 | return false; 83 | 84 | if (!efuse[MT_EE_XTAL_WF_RFCAL]) 85 | return false; 86 | 87 | return true; 88 | } 89 | 90 | static void 91 | mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse) 92 | { 93 | static const u8 cal_free_bytes[] = { 94 | MT_EE_TEMP_SENSOR_CAL, 95 | MT_EE_CP_FT_VERSION, 96 | MT_EE_XTAL_FREQ_OFFSET, 97 | MT_EE_XTAL_WF_RFCAL, 98 | /* Skip for MT7628 */ 99 | MT_EE_TX_POWER_0_START_2G, 100 | MT_EE_TX_POWER_0_START_2G + 1, 101 | MT_EE_TX_POWER_1_START_2G, 102 | MT_EE_TX_POWER_1_START_2G + 1, 103 | }; 104 | struct device_node *np = dev->mt76.dev->of_node; 105 | u8 *eeprom = dev->mt76.eeprom.data; 106 | int n = ARRAY_SIZE(cal_free_bytes); 107 | int i; 108 | 109 | if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) 110 | return; 111 | 112 | if (!mt7603_has_cal_free_data(dev, efuse)) 113 | return; 114 | 115 | if (is_mt7628(dev)) 116 | n -= 4; 117 | 118 | for (i = 0; i < n; i++) { 119 | int offset = cal_free_bytes[i]; 120 | 121 | eeprom[offset] = efuse[offset]; 122 | } 123 | } 124 | 125 | static int 126 | mt7603_eeprom_load(struct mt7603_dev *dev) 127 | { 128 | int ret; 129 | 130 | ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE); 131 | if (ret < 0) 132 | return ret; 133 | 134 | return mt7603_efuse_init(dev); 135 | } 136 | 137 | static int mt7603_check_eeprom(struct mt76_dev *dev) 138 | { 139 | u16 val = get_unaligned_le16(dev->eeprom.data); 140 | 141 | switch (val) { 142 | case 0x7628: 143 | case 0x7603: 144 | case 0x7600: 145 | return 0; 146 | default: 147 | return -EINVAL; 148 | } 149 | } 150 | 151 | static inline bool is_mt7688(struct mt7603_dev *dev) 152 | { 153 | return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4); 154 | } 155 | 156 | int mt7603_eeprom_init(struct mt7603_dev *dev) 157 | { 158 | u8 *eeprom; 159 | int ret; 160 | 161 | ret = mt7603_eeprom_load(dev); 162 | if (ret < 0) 163 | return ret; 164 | 165 | if (dev->mt76.otp.data) { 166 | if (mt7603_check_eeprom(&dev->mt76) == 0) 167 | mt7603_apply_cal_free_data(dev, dev->mt76.otp.data); 168 | else 169 | memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, 170 | MT7603_EEPROM_SIZE); 171 | } 172 | 173 | eeprom = (u8 *)dev->mt76.eeprom.data; 174 | dev->mphy.cap.has_2ghz = true; 175 | memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN); 176 | 177 | /* Check for 1SS devices */ 178 | dev->mphy.antenna_mask = 3; 179 | if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 || 180 | FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 || 181 | is_mt7688(dev)) 182 | dev->mphy.antenna_mask = 1; 183 | 184 | mt76_eeprom_override(&dev->mphy); 185 | 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /mt7603/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | 3 | #ifndef __MT7603_EEPROM_H 4 | #define __MT7603_EEPROM_H 5 | 6 | #include "mt7603.h" 7 | 8 | enum mt7603_eeprom_field { 9 | MT_EE_CHIP_ID = 0x000, 10 | MT_EE_VERSION = 0x002, 11 | MT_EE_MAC_ADDR = 0x004, 12 | MT_EE_NIC_CONF_0 = 0x034, 13 | MT_EE_NIC_CONF_1 = 0x036, 14 | MT_EE_NIC_CONF_2 = 0x042, 15 | 16 | MT_EE_XTAL_TRIM_1 = 0x03a, 17 | 18 | MT_EE_RSSI_OFFSET_2G = 0x046, 19 | MT_EE_WIFI_RF_SETTING = 0x048, 20 | MT_EE_RSSI_OFFSET_5G = 0x04a, 21 | 22 | MT_EE_TX_POWER_DELTA_BW40 = 0x050, 23 | MT_EE_TX_POWER_DELTA_BW80 = 0x052, 24 | 25 | MT_EE_TX_POWER_EXT_PA_5G = 0x054, 26 | 27 | MT_EE_TEMP_SENSOR_CAL = 0x055, 28 | 29 | MT_EE_TX_POWER_0_START_2G = 0x056, 30 | MT_EE_TX_POWER_1_START_2G = 0x05c, 31 | 32 | /* used as byte arrays */ 33 | #define MT_TX_POWER_GROUP_SIZE_5G 5 34 | #define MT_TX_POWER_GROUPS_5G 6 35 | MT_EE_TX_POWER_0_START_5G = 0x062, 36 | 37 | MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074, 38 | MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076, 39 | 40 | MT_EE_TX_POWER_1_START_5G = 0x080, 41 | 42 | MT_EE_TX_POWER_CCK = 0x0a0, 43 | MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2, 44 | MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4, 45 | MT_EE_TX_POWER_OFDM_2G_54M = 0x0a6, 46 | MT_EE_TX_POWER_HT_BPSK_QPSK = 0x0a8, 47 | MT_EE_TX_POWER_HT_16_64_QAM = 0x0aa, 48 | MT_EE_TX_POWER_HT_64_QAM = 0x0ac, 49 | 50 | MT_EE_ELAN_RX_MODE_GAIN = 0x0c0, 51 | MT_EE_ELAN_RX_MODE_NF = 0x0c1, 52 | MT_EE_ELAN_RX_MODE_P1DB = 0x0c2, 53 | 54 | MT_EE_ELAN_BYPASS_MODE_GAIN = 0x0c3, 55 | MT_EE_ELAN_BYPASS_MODE_NF = 0x0c4, 56 | MT_EE_ELAN_BYPASS_MODE_P1DB = 0x0c5, 57 | 58 | MT_EE_STEP_NUM_NEG_6_7 = 0x0c6, 59 | MT_EE_STEP_NUM_NEG_4_5 = 0x0c8, 60 | MT_EE_STEP_NUM_NEG_2_3 = 0x0ca, 61 | MT_EE_STEP_NUM_NEG_0_1 = 0x0cc, 62 | 63 | MT_EE_REF_STEP_24G = 0x0ce, 64 | 65 | MT_EE_STEP_NUM_PLUS_1_2 = 0x0d0, 66 | MT_EE_STEP_NUM_PLUS_3_4 = 0x0d2, 67 | MT_EE_STEP_NUM_PLUS_5_6 = 0x0d4, 68 | MT_EE_STEP_NUM_PLUS_7 = 0x0d6, 69 | 70 | MT_EE_CP_FT_VERSION = 0x0f0, 71 | 72 | MT_EE_TX_POWER_TSSI_OFF = 0x0f2, 73 | 74 | MT_EE_XTAL_FREQ_OFFSET = 0x0f4, 75 | MT_EE_XTAL_TRIM_2_COMP = 0x0f5, 76 | MT_EE_XTAL_TRIM_3_COMP = 0x0f6, 77 | MT_EE_XTAL_WF_RFCAL = 0x0f7, 78 | 79 | __MT_EE_MAX 80 | }; 81 | 82 | enum mt7603_eeprom_source { 83 | MT_EE_SRC_PROM, 84 | MT_EE_SRC_EFUSE, 85 | MT_EE_SRC_FLASH, 86 | }; 87 | 88 | #define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0) 89 | #define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4) 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /mt7603/mcu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | 3 | #ifndef __MT7603_MCU_H 4 | #define __MT7603_MCU_H 5 | 6 | struct mt7603_mcu_txd { 7 | __le16 len; 8 | __le16 pq_id; 9 | 10 | u8 cid; 11 | u8 pkt_type; 12 | u8 set_query; 13 | u8 seq; 14 | 15 | u8 uc_d2b0_rev; 16 | u8 ext_cid; 17 | u8 uc_d2b2_rev; 18 | u8 ext_cid_ack; 19 | 20 | u32 au4_d3_to_d7_rev[5]; 21 | } __packed __aligned(4); 22 | 23 | struct mt7603_mcu_rxd { 24 | __le16 len; 25 | __le16 pkt_type_id; 26 | 27 | u8 eid; 28 | u8 seq; 29 | __le16 __rsv; 30 | 31 | u8 ext_eid; 32 | u8 __rsv1[3]; 33 | }; 34 | 35 | #define MCU_PKT_ID 0xa0 36 | #define MCU_PORT_QUEUE 0x8000 37 | #define MCU_PORT_QUEUE_FW 0xc000 38 | 39 | #define MCU_FIRMWARE_ADDRESS 0x100000 40 | 41 | enum { 42 | MCU_Q_QUERY, 43 | MCU_Q_SET, 44 | MCU_Q_RESERVED, 45 | MCU_Q_NA 46 | }; 47 | 48 | enum { 49 | MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, 50 | MCU_CMD_FW_START_REQ = 0x02, 51 | MCU_CMD_INIT_ACCESS_REG = 0x3, 52 | MCU_CMD_PATCH_START_REQ = 0x05, 53 | MCU_CMD_PATCH_FINISH_REQ = 0x07, 54 | MCU_CMD_PATCH_SEM_CONTROL = 0x10, 55 | MCU_CMD_HIF_LOOPBACK = 0x20, 56 | MCU_CMD_CH_PRIVILEGE = 0x20, 57 | MCU_CMD_ACCESS_REG = 0xC2, 58 | MCU_CMD_EXT_CID = 0xED, 59 | MCU_CMD_FW_SCATTER = 0xEE, 60 | MCU_CMD_RESTART_DL_REQ = 0xEF, 61 | }; 62 | 63 | enum { 64 | MCU_EXT_CMD_RF_REG_ACCESS = 0x02, 65 | MCU_EXT_CMD_RF_TEST = 0x04, 66 | MCU_EXT_CMD_RADIO_ON_OFF_CTRL = 0x05, 67 | MCU_EXT_CMD_WIFI_RX_DISABLE = 0x06, 68 | MCU_EXT_CMD_PM_STATE_CTRL = 0x07, 69 | MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, 70 | MCU_EXT_CMD_NIC_CAPABILITY = 0x09, 71 | MCU_EXT_CMD_PWR_SAVING = 0x0A, 72 | MCU_EXT_CMD_MULTIPLE_REG_ACCESS = 0x0E, 73 | MCU_EXT_CMD_AP_PWR_SAVING_CAPABILITY = 0xF, 74 | MCU_EXT_CMD_SEC_ADDREMOVE_KEY = 0x10, 75 | MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, 76 | MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, 77 | MCU_EXT_CMD_PS_RETRIEVE_START = 0x14, 78 | MCU_EXT_CMD_LED_CTRL = 0x17, 79 | MCU_EXT_CMD_PACKET_FILTER = 0x18, 80 | MCU_EXT_CMD_PWR_MGT_BIT_WIFI = 0x1B, 81 | MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, 82 | MCU_EXT_CMD_THERMAL_PROTECT = 0x23, 83 | MCU_EXT_CMD_EDCA_SET = 0x27, 84 | MCU_EXT_CMD_SLOT_TIME_SET = 0x28, 85 | MCU_EXT_CMD_CONFIG_INTERNAL_SETTING = 0x29, 86 | MCU_EXT_CMD_NOA_OFFLOAD_CTRL = 0x2B, 87 | MCU_EXT_CMD_GET_THEMAL_SENSOR = 0x2C, 88 | MCU_EXT_CMD_WAKEUP_OPTION = 0x2E, 89 | MCU_EXT_CMD_AC_QUEUE_CONTROL = 0x31, 90 | MCU_EXT_CMD_BCN_UPDATE = 0x33 91 | }; 92 | 93 | enum { 94 | MCU_EXT_EVENT_CMD_RESULT = 0x0, 95 | MCU_EXT_EVENT_RF_REG_ACCESS = 0x2, 96 | MCU_EXT_EVENT_MULTI_CR_ACCESS = 0x0E, 97 | MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, 98 | MCU_EXT_EVENT_BEACON_LOSS = 0x1A, 99 | MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, 100 | MCU_EXT_EVENT_BCN_UPDATE = 0x31, 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /mt7603/pci.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "mt7603.h" 8 | 9 | static const struct pci_device_id mt76pci_device_table[] = { 10 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7603) }, 11 | { }, 12 | }; 13 | 14 | static int 15 | mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 16 | { 17 | struct mt7603_dev *dev; 18 | struct mt76_dev *mdev; 19 | int ret; 20 | 21 | ret = pcim_enable_device(pdev); 22 | if (ret) 23 | return ret; 24 | 25 | ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 26 | if (ret) 27 | return ret; 28 | 29 | pci_set_master(pdev); 30 | 31 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 32 | if (ret) 33 | return ret; 34 | 35 | mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops, 36 | &mt7603_drv_ops); 37 | if (!mdev) 38 | return -ENOMEM; 39 | 40 | dev = container_of(mdev, struct mt7603_dev, mt76); 41 | mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); 42 | 43 | mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | 44 | (mt76_rr(dev, MT_HW_REV) & 0xff); 45 | dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 46 | 47 | mt76_wr(dev, MT_INT_MASK_CSR, 0); 48 | 49 | ret = devm_request_irq(mdev->dev, pdev->irq, mt7603_irq_handler, 50 | IRQF_SHARED, KBUILD_MODNAME, dev); 51 | if (ret) 52 | goto error; 53 | 54 | ret = mt7603_register_device(dev); 55 | if (ret) 56 | goto error; 57 | 58 | return 0; 59 | error: 60 | mt76_free_device(&dev->mt76); 61 | 62 | return ret; 63 | } 64 | 65 | static void 66 | mt76pci_remove(struct pci_dev *pdev) 67 | { 68 | struct mt76_dev *mdev = pci_get_drvdata(pdev); 69 | struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 70 | 71 | mt7603_unregister_device(dev); 72 | } 73 | 74 | MODULE_DEVICE_TABLE(pci, mt76pci_device_table); 75 | MODULE_FIRMWARE(MT7603_FIRMWARE_E1); 76 | MODULE_FIRMWARE(MT7603_FIRMWARE_E2); 77 | 78 | struct pci_driver mt7603_pci_driver = { 79 | .name = KBUILD_MODNAME, 80 | .id_table = mt76pci_device_table, 81 | .probe = mt76pci_probe, 82 | .remove = mt76pci_remove, 83 | }; 84 | -------------------------------------------------------------------------------- /mt7603/soc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "mt7603.h" 8 | 9 | static int 10 | mt76_wmac_probe(struct platform_device *pdev) 11 | { 12 | struct mt7603_dev *dev; 13 | void __iomem *mem_base; 14 | struct mt76_dev *mdev; 15 | int irq; 16 | int ret; 17 | 18 | irq = platform_get_irq(pdev, 0); 19 | if (irq < 0) 20 | return irq; 21 | 22 | mem_base = devm_platform_ioremap_resource(pdev, 0); 23 | if (IS_ERR(mem_base)) 24 | return PTR_ERR(mem_base); 25 | 26 | mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops, 27 | &mt7603_drv_ops); 28 | if (!mdev) 29 | return -ENOMEM; 30 | 31 | dev = container_of(mdev, struct mt7603_dev, mt76); 32 | mt76_mmio_init(mdev, mem_base); 33 | 34 | mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | 35 | (mt76_rr(dev, MT_HW_REV) & 0xff); 36 | dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 37 | 38 | mt76_wr(dev, MT_INT_MASK_CSR, 0); 39 | 40 | ret = devm_request_irq(mdev->dev, irq, mt7603_irq_handler, 41 | IRQF_SHARED, KBUILD_MODNAME, dev); 42 | if (ret) 43 | goto error; 44 | 45 | ret = mt7603_register_device(dev); 46 | if (ret) 47 | goto error; 48 | 49 | return 0; 50 | error: 51 | ieee80211_free_hw(mt76_hw(dev)); 52 | return ret; 53 | } 54 | 55 | static int 56 | mt76_wmac_remove(struct platform_device *pdev) 57 | { 58 | struct mt76_dev *mdev = platform_get_drvdata(pdev); 59 | struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 60 | 61 | mt7603_unregister_device(dev); 62 | 63 | return 0; 64 | } 65 | 66 | static const struct of_device_id of_wmac_match[] = { 67 | { .compatible = "mediatek,mt7628-wmac" }, 68 | {}, 69 | }; 70 | 71 | MODULE_DEVICE_TABLE(of, of_wmac_match); 72 | MODULE_FIRMWARE(MT7628_FIRMWARE_E1); 73 | MODULE_FIRMWARE(MT7628_FIRMWARE_E2); 74 | 75 | struct platform_driver mt76_wmac_driver = { 76 | .probe = mt76_wmac_probe, 77 | .remove = mt76_wmac_remove, 78 | .driver = { 79 | .name = "mt76_wmac", 80 | .of_match_table = of_wmac_match, 81 | }, 82 | }; 83 | -------------------------------------------------------------------------------- /mt7615/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | 3 | config MT7615_COMMON 4 | tristate 5 | select WANT_DEV_COREDUMP 6 | select MT76_CONNAC_LIB 7 | 8 | config MT7615E 9 | tristate "MediaTek MT7615E and MT7663E (PCIe) support" 10 | select MT7615_COMMON 11 | depends on MAC80211 12 | depends on PCI 13 | help 14 | This adds support for MT7615-based wireless PCIe devices, 15 | which support concurrent dual-band operation at both 5GHz 16 | and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2 17 | MU-MIMO up to 4 users/group and 160MHz channels. 18 | 19 | To compile this driver as a module, choose M here. 20 | 21 | config MT7622_WMAC 22 | bool "MT7622 (SoC) WMAC support" 23 | depends on MT7615E 24 | depends on ARCH_MEDIATEK || COMPILE_TEST 25 | select REGMAP 26 | default y 27 | help 28 | This adds support for the built-in WMAC on MT7622 SoC devices 29 | which has the same feature set as a MT7615, but limited to 30 | 2.4 GHz only. 31 | 32 | config MT7663_USB_SDIO_COMMON 33 | tristate 34 | select MT7615_COMMON 35 | 36 | config MT7663U 37 | tristate "MediaTek MT7663U (USB) support" 38 | select MT76_USB 39 | select MT7663_USB_SDIO_COMMON 40 | depends on MAC80211 41 | depends on USB 42 | help 43 | This adds support for MT7663U 802.11ac 2x2:2 wireless devices. 44 | 45 | To compile this driver as a module, choose M here. 46 | 47 | config MT7663S 48 | tristate "MediaTek MT7663S (SDIO) support" 49 | select MT76_SDIO 50 | select MT7663_USB_SDIO_COMMON 51 | depends on MAC80211 52 | depends on MMC 53 | help 54 | This adds support for MT7663S 802.11ac 2x2:2 wireless devices. 55 | 56 | To compile this driver as a module, choose M here. 57 | -------------------------------------------------------------------------------- /mt7615/Makefile: -------------------------------------------------------------------------------- 1 | #SPDX-License-Identifier: ISC 2 | 3 | EXTRA_CFLAGS += -DCONFIG_MT76_LEDS 4 | obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o 5 | obj-$(CONFIG_MT7615E) += mt7615e.o 6 | obj-$(CONFIG_MT7663_USB_SDIO_COMMON) += mt7663-usb-sdio-common.o 7 | obj-$(CONFIG_MT7663U) += mt7663u.o 8 | obj-$(CONFIG_MT7663S) += mt7663s.o 9 | 10 | CFLAGS_trace.o := -I$(src) 11 | 12 | mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \ 13 | debugfs.o trace.o 14 | mt7615-common-$(CONFIG_NL80211_TESTMODE) += testmode.o 15 | 16 | mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o 17 | mt7615e-$(CONFIG_MT7622_WMAC) += soc.o 18 | 19 | mt7663-usb-sdio-common-y := usb_sdio.o 20 | mt7663u-y := usb.o usb_mcu.o 21 | mt7663s-y := sdio.o sdio_mcu.o 22 | -------------------------------------------------------------------------------- /mt7615/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2019 MediaTek Inc. */ 3 | 4 | #ifndef __MT7615_EEPROM_H 5 | #define __MT7615_EEPROM_H 6 | 7 | #include "mt7615.h" 8 | 9 | 10 | #define MT7615_EEPROM_DCOC_OFFSET MT7615_EEPROM_SIZE 11 | #define MT7615_EEPROM_DCOC_SIZE 256 12 | #define MT7615_EEPROM_DCOC_COUNT 34 13 | 14 | #define MT7615_EEPROM_TXDPD_OFFSET (MT7615_EEPROM_SIZE + \ 15 | MT7615_EEPROM_DCOC_COUNT * \ 16 | MT7615_EEPROM_DCOC_SIZE) 17 | #define MT7615_EEPROM_TXDPD_SIZE 216 18 | #define MT7615_EEPROM_TXDPD_COUNT (44 + 3) 19 | 20 | #define MT7615_EEPROM_FULL_SIZE (MT7615_EEPROM_TXDPD_OFFSET + \ 21 | MT7615_EEPROM_TXDPD_COUNT * \ 22 | MT7615_EEPROM_TXDPD_SIZE) 23 | 24 | enum mt7615_eeprom_field { 25 | MT_EE_CHIP_ID = 0x000, 26 | MT_EE_VERSION = 0x002, 27 | MT_EE_MAC_ADDR = 0x004, 28 | MT_EE_NIC_CONF_0 = 0x034, 29 | MT_EE_NIC_CONF_1 = 0x036, 30 | MT_EE_WIFI_CONF = 0x03e, 31 | MT_EE_CALDATA_FLASH = 0x052, 32 | MT_EE_TX0_2G_TARGET_POWER = 0x058, 33 | MT_EE_TX0_5G_G0_TARGET_POWER = 0x070, 34 | MT7663_EE_5G_RATE_POWER = 0x089, 35 | MT_EE_TX1_5G_G0_TARGET_POWER = 0x098, 36 | MT_EE_2G_RATE_POWER = 0x0be, 37 | MT_EE_5G_RATE_POWER = 0x0d5, 38 | MT7663_EE_TX0_2G_TARGET_POWER = 0x0e3, 39 | MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2, 40 | MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3, 41 | MT_EE_TX2_5G_G0_TARGET_POWER = 0x142, 42 | MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a, 43 | MT7663_EE_HW_CONF1 = 0x1b0, 44 | MT7663_EE_TX0_5G_G0_TARGET_POWER = 0x245, 45 | MT7663_EE_TX1_5G_G0_TARGET_POWER = 0x2b5, 46 | 47 | MT7615_EE_MAX = 0x3bf, 48 | MT7622_EE_MAX = 0x3db, 49 | MT7663_EE_MAX = 0x400, 50 | }; 51 | 52 | #define MT_EE_RATE_POWER_MASK GENMASK(5, 0) 53 | #define MT_EE_RATE_POWER_SIGN BIT(6) 54 | #define MT_EE_RATE_POWER_EN BIT(7) 55 | 56 | #define MT_EE_CALDATA_FLASH_TX_DPD BIT(0) 57 | #define MT_EE_CALDATA_FLASH_RX_CAL BIT(1) 58 | 59 | #define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4) 60 | #define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0) 61 | 62 | #define MT_EE_HW_CONF1_TX_MASK GENMASK(2, 0) 63 | 64 | #define MT_EE_NIC_CONF_TSSI_2G BIT(5) 65 | #define MT_EE_NIC_CONF_TSSI_5G BIT(6) 66 | 67 | #define MT_EE_NIC_WIFI_CONF_BAND_SEL GENMASK(5, 4) 68 | enum mt7615_eeprom_band { 69 | MT_EE_DUAL_BAND, 70 | MT_EE_5GHZ, 71 | MT_EE_2GHZ, 72 | MT_EE_DBDC, 73 | }; 74 | 75 | enum mt7615_channel_group { 76 | MT_CH_5G_JAPAN, 77 | MT_CH_5G_UNII_1, 78 | MT_CH_5G_UNII_2A, 79 | MT_CH_5G_UNII_2B, 80 | MT_CH_5G_UNII_2E_1, 81 | MT_CH_5G_UNII_2E_2, 82 | MT_CH_5G_UNII_2E_3, 83 | MT_CH_5G_UNII_3, 84 | __MT_CH_MAX 85 | }; 86 | 87 | static inline enum mt7615_channel_group 88 | mt7615_get_channel_group(int channel) 89 | { 90 | if (channel >= 184 && channel <= 196) 91 | return MT_CH_5G_JAPAN; 92 | if (channel <= 48) 93 | return MT_CH_5G_UNII_1; 94 | if (channel <= 64) 95 | return MT_CH_5G_UNII_2A; 96 | if (channel <= 114) 97 | return MT_CH_5G_UNII_2E_1; 98 | if (channel <= 144) 99 | return MT_CH_5G_UNII_2E_2; 100 | if (channel <= 161) 101 | return MT_CH_5G_UNII_2E_3; 102 | return MT_CH_5G_UNII_3; 103 | } 104 | 105 | static inline bool 106 | mt7615_ext_pa_enabled(struct mt7615_dev *dev, enum nl80211_band band) 107 | { 108 | u8 *eep = dev->mt76.eeprom.data; 109 | 110 | if (band == NL80211_BAND_5GHZ) 111 | return !(eep[MT_EE_NIC_CONF_1 + 1] & MT_EE_NIC_CONF_TSSI_5G); 112 | else 113 | return !(eep[MT_EE_NIC_CONF_1 + 1] & MT_EE_NIC_CONF_TSSI_2G); 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /mt7615/mt7615_trace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2019 Lorenzo Bianconi 4 | */ 5 | 6 | #if !defined(__MT7615_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 7 | #define __MT7615_TRACE_H 8 | 9 | #include 10 | #include "mt7615.h" 11 | 12 | #undef TRACE_SYSTEM 13 | #define TRACE_SYSTEM mt7615 14 | 15 | #define MAXNAME 32 16 | #define DEV_ENTRY __array(char, wiphy_name, 32) 17 | #define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ 18 | wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) 19 | #define DEV_PR_FMT "%s" 20 | #define DEV_PR_ARG __entry->wiphy_name 21 | 22 | #define TOKEN_ENTRY __field(u16, token) 23 | #define TOKEN_ASSIGN __entry->token = token 24 | #define TOKEN_PR_FMT " %d" 25 | #define TOKEN_PR_ARG __entry->token 26 | 27 | DECLARE_EVENT_CLASS(dev_token, 28 | TP_PROTO(struct mt7615_dev *dev, u16 token), 29 | TP_ARGS(dev, token), 30 | TP_STRUCT__entry( 31 | DEV_ENTRY 32 | TOKEN_ENTRY 33 | ), 34 | TP_fast_assign( 35 | DEV_ASSIGN; 36 | TOKEN_ASSIGN; 37 | ), 38 | TP_printk( 39 | DEV_PR_FMT TOKEN_PR_FMT, 40 | DEV_PR_ARG, TOKEN_PR_ARG 41 | ) 42 | ); 43 | 44 | DEFINE_EVENT(dev_token, mac_tx_free, 45 | TP_PROTO(struct mt7615_dev *dev, u16 token), 46 | TP_ARGS(dev, token) 47 | ); 48 | 49 | #endif 50 | 51 | #undef TRACE_INCLUDE_PATH 52 | #define TRACE_INCLUDE_PATH . 53 | #undef TRACE_INCLUDE_FILE 54 | #define TRACE_INCLUDE_FILE mt7615_trace 55 | 56 | #include 57 | -------------------------------------------------------------------------------- /mt7615/pci_init.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2019 MediaTek Inc. 3 | * 4 | * Author: Roy Luo 5 | * Ryder Lee 6 | * Felix Fietkau 7 | * Lorenzo Bianconi 8 | */ 9 | 10 | #include 11 | #include "mt7615.h" 12 | #include "mac.h" 13 | #include "eeprom.h" 14 | 15 | static void mt7615_pci_init_work(struct work_struct *work) 16 | { 17 | struct mt7615_dev *dev = container_of(work, struct mt7615_dev, 18 | mcu_work); 19 | int i, ret; 20 | 21 | ret = mt7615_mcu_init(dev); 22 | for (i = 0; (ret == -EAGAIN) && (i < 10); i++) { 23 | msleep(200); 24 | ret = mt7615_mcu_init(dev); 25 | } 26 | 27 | if (ret) 28 | return; 29 | 30 | mt7615_init_work(dev); 31 | } 32 | 33 | static int mt7615_init_hardware(struct mt7615_dev *dev) 34 | { 35 | u32 addr = mt7615_reg_map(dev, MT_EFUSE_BASE); 36 | int ret, idx; 37 | 38 | mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); 39 | 40 | INIT_WORK(&dev->mcu_work, mt7615_pci_init_work); 41 | ret = mt7615_eeprom_init(dev, addr); 42 | if (ret < 0) 43 | return ret; 44 | 45 | if (is_mt7663(&dev->mt76)) { 46 | /* Reset RGU */ 47 | mt76_clear(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1)); 48 | mt76_set(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1)); 49 | } 50 | 51 | ret = mt7615_dma_init(dev); 52 | if (ret) 53 | return ret; 54 | 55 | set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); 56 | 57 | /* Beacon and mgmt frames should occupy wcid 0 */ 58 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); 59 | if (idx) 60 | return -ENOSPC; 61 | 62 | dev->mt76.global_wcid.idx = idx; 63 | dev->mt76.global_wcid.hw_key_idx = -1; 64 | rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); 65 | 66 | return 0; 67 | } 68 | 69 | static void 70 | mt7615_led_set_config(struct led_classdev *led_cdev, 71 | u8 delay_on, u8 delay_off) 72 | { 73 | struct mt7615_dev *dev; 74 | struct mt76_dev *mt76; 75 | u32 val, addr; 76 | 77 | mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); 78 | dev = container_of(mt76, struct mt7615_dev, mt76); 79 | 80 | if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) 81 | return; 82 | 83 | val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | 84 | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | 85 | FIELD_PREP(MT_LED_STATUS_ON, delay_on); 86 | 87 | addr = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); 88 | mt76_wr(dev, addr, val); 89 | addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); 90 | mt76_wr(dev, addr, val); 91 | 92 | val = MT_LED_CTRL_REPLAY(mt76->led_pin) | 93 | MT_LED_CTRL_KICK(mt76->led_pin); 94 | if (mt76->led_al) 95 | val |= MT_LED_CTRL_POLARITY(mt76->led_pin); 96 | addr = mt7615_reg_map(dev, MT_LED_CTRL); 97 | mt76_wr(dev, addr, val); 98 | 99 | mt76_connac_pm_unref(&dev->mphy, &dev->pm); 100 | } 101 | 102 | static int 103 | mt7615_led_set_blink(struct led_classdev *led_cdev, 104 | unsigned long *delay_on, 105 | unsigned long *delay_off) 106 | { 107 | u8 delta_on, delta_off; 108 | 109 | delta_off = max_t(u8, *delay_off / 10, 1); 110 | delta_on = max_t(u8, *delay_on / 10, 1); 111 | 112 | mt7615_led_set_config(led_cdev, delta_on, delta_off); 113 | 114 | return 0; 115 | } 116 | 117 | static void 118 | mt7615_led_set_brightness(struct led_classdev *led_cdev, 119 | enum led_brightness brightness) 120 | { 121 | if (!brightness) 122 | mt7615_led_set_config(led_cdev, 0, 0xff); 123 | else 124 | mt7615_led_set_config(led_cdev, 0xff, 0); 125 | } 126 | 127 | int mt7615_register_device(struct mt7615_dev *dev) 128 | { 129 | int ret; 130 | 131 | mt7615_init_device(dev); 132 | INIT_WORK(&dev->reset_work, mt7615_mac_reset_work); 133 | 134 | /* init led callbacks */ 135 | if (IS_ENABLED(CONFIG_MT76_LEDS)) { 136 | dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness; 137 | dev->mt76.led_cdev.blink_set = mt7615_led_set_blink; 138 | } 139 | 140 | ret = mt7622_wmac_init(dev); 141 | if (ret) 142 | return ret; 143 | 144 | ret = mt7615_init_hardware(dev); 145 | if (ret) 146 | return ret; 147 | 148 | ret = mt76_register_device(&dev->mt76, true, mt76_rates, 149 | ARRAY_SIZE(mt76_rates)); 150 | if (ret) 151 | return ret; 152 | 153 | ret = mt7615_thermal_init(dev); 154 | if (ret) 155 | return ret; 156 | 157 | ieee80211_queue_work(mt76_hw(dev), &dev->mcu_work); 158 | mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); 159 | mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); 160 | 161 | if (dev->dbdc_support) { 162 | ret = mt7615_register_ext_phy(dev); 163 | if (ret) 164 | return ret; 165 | } 166 | 167 | return mt7615_init_debugfs(dev); 168 | } 169 | 170 | void mt7615_unregister_device(struct mt7615_dev *dev) 171 | { 172 | bool mcu_running; 173 | 174 | mcu_running = mt7615_wait_for_mcu_init(dev); 175 | 176 | mt7615_unregister_ext_phy(dev); 177 | mt76_unregister_device(&dev->mt76); 178 | if (mcu_running) 179 | mt7615_mcu_exit(dev); 180 | 181 | mt7615_tx_token_put(dev); 182 | mt7615_dma_cleanup(dev); 183 | tasklet_disable(&dev->irq_tasklet); 184 | 185 | mt76_free_device(&dev->mt76); 186 | } 187 | -------------------------------------------------------------------------------- /mt7615/sdio_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* Copyright (C) 2020 MediaTek Inc. 3 | * 4 | * Author: Felix Fietkau 5 | * Lorenzo Bianconi 6 | * Sean Wang 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "../sdio.h" 14 | #include "mt7615.h" 15 | #include "mac.h" 16 | #include "mcu.h" 17 | #include "regs.h" 18 | 19 | static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) 20 | { 21 | struct mt76_sdio *sdio = &dev->mt76.sdio; 22 | u32 txdwcnt; 23 | 24 | sdio->sched.pse_data_quota = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, 25 | MT_HIF0_MIN_QUOTA); 26 | sdio->sched.pse_mcu_quota = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, 27 | MT_HIF1_MIN_QUOTA); 28 | sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, 29 | MT_HIF0_MIN_QUOTA); 30 | sdio->sched.pse_page_size = MT_PSE_PAGE_SZ; 31 | txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, 32 | MT_PP_TXDWCNT_TX1_ADD_DW_CNT); 33 | sdio->sched.deficit = txdwcnt << 2; 34 | 35 | return 0; 36 | } 37 | 38 | static int 39 | mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 40 | int cmd, int *seq) 41 | { 42 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 43 | int ret; 44 | 45 | mt7615_mcu_fill_msg(dev, skb, cmd, seq); 46 | ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0); 47 | if (ret) 48 | return ret; 49 | 50 | mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]); 51 | 52 | return ret; 53 | } 54 | 55 | static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 56 | { 57 | struct sdio_func *func = dev->mt76.sdio.func; 58 | struct mt76_phy *mphy = &dev->mt76.phy; 59 | struct mt76_connac_pm *pm = &dev->pm; 60 | u32 status; 61 | int ret; 62 | 63 | sdio_claim_host(func); 64 | 65 | sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 66 | 67 | ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 68 | status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 69 | if (ret < 0) { 70 | dev_err(dev->mt76.dev, "Cannot get ownership from device"); 71 | } else { 72 | clear_bit(MT76_STATE_PM, &mphy->state); 73 | 74 | pm->stats.last_wake_event = jiffies; 75 | pm->stats.doze_time += pm->stats.last_wake_event - 76 | pm->stats.last_doze_event; 77 | } 78 | sdio_release_host(func); 79 | 80 | return ret; 81 | } 82 | 83 | static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 84 | { 85 | struct mt76_phy *mphy = &dev->mt76.phy; 86 | int ret = 0; 87 | 88 | mutex_lock(&dev->pm.mutex); 89 | 90 | if (test_bit(MT76_STATE_PM, &mphy->state)) 91 | ret = __mt7663s_mcu_drv_pmctrl(dev); 92 | 93 | mutex_unlock(&dev->pm.mutex); 94 | 95 | return ret; 96 | } 97 | 98 | static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) 99 | { 100 | struct sdio_func *func = dev->mt76.sdio.func; 101 | struct mt76_phy *mphy = &dev->mt76.phy; 102 | struct mt76_connac_pm *pm = &dev->pm; 103 | int ret = 0; 104 | u32 status; 105 | 106 | mutex_lock(&pm->mutex); 107 | 108 | if (mt76_connac_skip_fw_pmctrl(mphy, pm)) 109 | goto out; 110 | 111 | sdio_claim_host(func); 112 | 113 | sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 114 | 115 | ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 116 | !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 117 | if (ret < 0) { 118 | dev_err(dev->mt76.dev, "Cannot set ownership to device"); 119 | clear_bit(MT76_STATE_PM, &mphy->state); 120 | } else { 121 | pm->stats.last_doze_event = jiffies; 122 | pm->stats.awake_time += pm->stats.last_doze_event - 123 | pm->stats.last_wake_event; 124 | } 125 | 126 | sdio_release_host(func); 127 | out: 128 | mutex_unlock(&pm->mutex); 129 | 130 | return ret; 131 | } 132 | 133 | int mt7663s_mcu_init(struct mt7615_dev *dev) 134 | { 135 | static const struct mt76_mcu_ops mt7663s_mcu_ops = { 136 | .headroom = sizeof(struct mt7615_mcu_txd), 137 | .tailroom = MT_USB_TAIL_SIZE, 138 | .mcu_skb_send_msg = mt7663s_mcu_send_message, 139 | .mcu_parse_response = mt7615_mcu_parse_response, 140 | .mcu_restart = mt7615_mcu_restart, 141 | .mcu_rr = mt76_connac_mcu_reg_rr, 142 | .mcu_wr = mt76_connac_mcu_reg_wr, 143 | }; 144 | struct mt7615_mcu_ops *mcu_ops; 145 | int ret; 146 | 147 | ret = __mt7663s_mcu_drv_pmctrl(dev); 148 | if (ret) 149 | return ret; 150 | 151 | dev->mt76.mcu_ops = &mt7663s_mcu_ops, 152 | 153 | ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 154 | if (ret) { 155 | mt7615_mcu_restart(&dev->mt76); 156 | if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 157 | MT_TOP_MISC2_FW_N9_RDY, 0, 500)) 158 | return -EIO; 159 | } 160 | 161 | ret = __mt7663_load_firmware(dev); 162 | if (ret) 163 | return ret; 164 | 165 | mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops), 166 | GFP_KERNEL); 167 | if (!mcu_ops) 168 | return -ENOMEM; 169 | 170 | mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl; 171 | mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl; 172 | dev->mcu_ops = mcu_ops; 173 | 174 | ret = mt7663s_mcu_init_sched(dev); 175 | if (ret) 176 | return ret; 177 | 178 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 179 | 180 | return 0; 181 | } 182 | -------------------------------------------------------------------------------- /mt7615/soc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2019 MediaTek Inc. 3 | * 4 | * Author: Ryder Lee 5 | * Felix Fietkau 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "mt7615.h" 15 | 16 | int mt7622_wmac_init(struct mt7615_dev *dev) 17 | { 18 | struct device_node *np = dev->mt76.dev->of_node; 19 | 20 | if (!is_mt7622(&dev->mt76)) 21 | return 0; 22 | 23 | dev->infracfg = syscon_regmap_lookup_by_phandle(np, "mediatek,infracfg"); 24 | if (IS_ERR(dev->infracfg)) { 25 | dev_err(dev->mt76.dev, "Cannot find infracfg controller\n"); 26 | return PTR_ERR(dev->infracfg); 27 | } 28 | 29 | return 0; 30 | } 31 | 32 | static int mt7622_wmac_probe(struct platform_device *pdev) 33 | { 34 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 35 | void __iomem *mem_base; 36 | int irq; 37 | 38 | irq = platform_get_irq(pdev, 0); 39 | if (irq < 0) 40 | return irq; 41 | 42 | mem_base = devm_ioremap_resource(&pdev->dev, res); 43 | if (IS_ERR(mem_base)) 44 | return PTR_ERR(mem_base); 45 | 46 | return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); 47 | } 48 | 49 | static int mt7622_wmac_remove(struct platform_device *pdev) 50 | { 51 | struct mt7615_dev *dev = platform_get_drvdata(pdev); 52 | 53 | mt7615_unregister_device(dev); 54 | 55 | return 0; 56 | } 57 | 58 | static const struct of_device_id mt7622_wmac_of_match[] = { 59 | { .compatible = "mediatek,mt7622-wmac" }, 60 | {}, 61 | }; 62 | 63 | struct platform_driver mt7622_wmac_driver = { 64 | .driver = { 65 | .name = "mt7622-wmac", 66 | .of_match_table = mt7622_wmac_of_match, 67 | }, 68 | .probe = mt7622_wmac_probe, 69 | .remove = mt7622_wmac_remove, 70 | }; 71 | 72 | MODULE_FIRMWARE(MT7622_FIRMWARE_N9); 73 | MODULE_FIRMWARE(MT7622_ROM_PATCH); 74 | -------------------------------------------------------------------------------- /mt7615/trace.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2019 Lorenzo Bianconi 4 | */ 5 | 6 | #include 7 | 8 | #ifndef __CHECKER__ 9 | #define CREATE_TRACE_POINTS 10 | #include "mt7615_trace.h" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /mt7615/usb_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* Copyright (C) 2019 MediaTek Inc. 3 | * 4 | * Author: Felix Fietkau 5 | * Lorenzo Bianconi 6 | * Sean Wang 7 | */ 8 | #include 9 | #include 10 | 11 | #include "mt7615.h" 12 | #include "mac.h" 13 | #include "mcu.h" 14 | #include "regs.h" 15 | 16 | static int 17 | mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 18 | int cmd, int *seq) 19 | { 20 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 21 | int ret, ep, len, pad; 22 | 23 | mt7615_mcu_fill_msg(dev, skb, cmd, seq); 24 | if (cmd != MCU_CMD(FW_SCATTER)) 25 | ep = MT_EP_OUT_INBAND_CMD; 26 | else 27 | ep = MT_EP_OUT_AC_BE; 28 | 29 | len = skb->len; 30 | put_unaligned_le32(len, skb_push(skb, sizeof(len))); 31 | pad = round_up(skb->len, 4) + 4 - skb->len; 32 | ret = mt76_skb_adjust_pad(skb, pad); 33 | if (ret < 0) 34 | goto out; 35 | 36 | ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 37 | 1000, ep); 38 | 39 | out: 40 | dev_kfree_skb(skb); 41 | 42 | return ret; 43 | } 44 | 45 | int mt7663u_mcu_init(struct mt7615_dev *dev) 46 | { 47 | static const struct mt76_mcu_ops mt7663u_mcu_ops = { 48 | .headroom = MT_USB_HDR_SIZE + sizeof(struct mt7615_mcu_txd), 49 | .tailroom = MT_USB_TAIL_SIZE, 50 | .mcu_skb_send_msg = mt7663u_mcu_send_message, 51 | .mcu_parse_response = mt7615_mcu_parse_response, 52 | .mcu_restart = mt7615_mcu_restart, 53 | }; 54 | int ret; 55 | 56 | dev->mt76.mcu_ops = &mt7663u_mcu_ops, 57 | 58 | mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 59 | if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { 60 | mt7615_mcu_restart(&dev->mt76); 61 | if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 62 | MT_TOP_MISC2_FW_PWR_ON, 0, 500)) 63 | return -EIO; 64 | 65 | ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON, 66 | USB_DIR_OUT | USB_TYPE_VENDOR, 67 | 0x0, 0x1, NULL, 0); 68 | if (ret) 69 | return ret; 70 | 71 | if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 72 | MT_TOP_MISC2_FW_PWR_ON, 73 | FW_STATE_PWR_ON << 1, 500)) { 74 | dev_err(dev->mt76.dev, "Timeout for power on\n"); 75 | return -EIO; 76 | } 77 | } 78 | 79 | ret = __mt7663_load_firmware(dev); 80 | if (ret) 81 | return ret; 82 | 83 | mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 84 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /mt76_connac.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #ifndef __MT76_CONNAC_H 5 | #define __MT76_CONNAC_H 6 | 7 | #include "mt76.h" 8 | 9 | #define MT76_CONNAC_SCAN_IE_LEN 600 10 | #define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10 11 | #define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX 12 | #define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 13 | #define MT76_CONNAC_MAX_SCAN_MATCH 16 14 | 15 | #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) 16 | #define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) 17 | 18 | enum { 19 | CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, 20 | CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, 21 | CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80, 22 | CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160, 23 | CMD_CBW_10MHZ, 24 | CMD_CBW_5MHZ, 25 | CMD_CBW_8080MHZ, 26 | 27 | CMD_HE_MCS_BW80 = 0, 28 | CMD_HE_MCS_BW160, 29 | CMD_HE_MCS_BW8080, 30 | CMD_HE_MCS_BW_NUM 31 | }; 32 | 33 | enum { 34 | HW_BSSID_0 = 0x0, 35 | HW_BSSID_1, 36 | HW_BSSID_2, 37 | HW_BSSID_3, 38 | HW_BSSID_MAX = HW_BSSID_3, 39 | EXT_BSSID_START = 0x10, 40 | EXT_BSSID_1, 41 | EXT_BSSID_15 = 0x1f, 42 | EXT_BSSID_MAX = EXT_BSSID_15, 43 | REPEATER_BSSID_START = 0x20, 44 | REPEATER_BSSID_MAX = 0x3f, 45 | }; 46 | 47 | struct mt76_connac_pm { 48 | bool enable; 49 | bool ds_enable; 50 | bool suspended; 51 | 52 | spinlock_t txq_lock; 53 | struct { 54 | struct mt76_wcid *wcid; 55 | struct sk_buff *skb; 56 | } tx_q[IEEE80211_NUM_ACS]; 57 | 58 | struct work_struct wake_work; 59 | wait_queue_head_t wait; 60 | 61 | struct { 62 | spinlock_t lock; 63 | u32 count; 64 | } wake; 65 | struct mutex mutex; 66 | 67 | struct delayed_work ps_work; 68 | unsigned long last_activity; 69 | unsigned long idle_timeout; 70 | 71 | struct { 72 | unsigned long last_wake_event; 73 | unsigned long awake_time; 74 | unsigned long last_doze_event; 75 | unsigned long doze_time; 76 | unsigned int lp_wake; 77 | } stats; 78 | }; 79 | 80 | struct mt76_connac_coredump { 81 | struct sk_buff_head msg_list; 82 | struct delayed_work work; 83 | unsigned long last_activity; 84 | }; 85 | 86 | extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; 87 | 88 | static inline bool is_mt7922(struct mt76_dev *dev) 89 | { 90 | return mt76_chip(dev) == 0x7922; 91 | } 92 | 93 | static inline bool is_mt7921(struct mt76_dev *dev) 94 | { 95 | return mt76_chip(dev) == 0x7961 || is_mt7922(dev); 96 | } 97 | 98 | static inline bool is_mt7663(struct mt76_dev *dev) 99 | { 100 | return mt76_chip(dev) == 0x7663; 101 | } 102 | 103 | int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm); 104 | void mt76_connac_power_save_sched(struct mt76_phy *phy, 105 | struct mt76_connac_pm *pm); 106 | void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, 107 | struct mt76_wcid *wcid); 108 | 109 | static inline bool 110 | mt76_connac_pm_ref(struct mt76_phy *phy, struct mt76_connac_pm *pm) 111 | { 112 | bool ret = false; 113 | 114 | spin_lock_bh(&pm->wake.lock); 115 | if (test_bit(MT76_STATE_PM, &phy->state)) 116 | goto out; 117 | 118 | pm->wake.count++; 119 | ret = true; 120 | out: 121 | spin_unlock_bh(&pm->wake.lock); 122 | 123 | return ret; 124 | } 125 | 126 | static inline void 127 | mt76_connac_pm_unref(struct mt76_phy *phy, struct mt76_connac_pm *pm) 128 | { 129 | spin_lock_bh(&pm->wake.lock); 130 | 131 | pm->last_activity = jiffies; 132 | if (--pm->wake.count == 0 && 133 | test_bit(MT76_STATE_MCU_RUNNING, &phy->state)) 134 | mt76_connac_power_save_sched(phy, pm); 135 | 136 | spin_unlock_bh(&pm->wake.lock); 137 | } 138 | 139 | static inline bool 140 | mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm) 141 | { 142 | struct mt76_dev *dev = phy->dev; 143 | bool ret; 144 | 145 | if (dev->token_count) 146 | return true; 147 | 148 | spin_lock_bh(&pm->wake.lock); 149 | ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state); 150 | spin_unlock_bh(&pm->wake.lock); 151 | 152 | return ret; 153 | } 154 | 155 | static inline void 156 | mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm) 157 | __acquires(&dev->mutex) 158 | { 159 | mutex_lock(&dev->mutex); 160 | mt76_connac_pm_wake(&dev->phy, pm); 161 | } 162 | 163 | static inline void 164 | mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) 165 | __releases(&dev->mutex) 166 | { 167 | mt76_connac_power_save_sched(&dev->phy, pm); 168 | mutex_unlock(&dev->mutex); 169 | } 170 | 171 | void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, 172 | struct mt76_connac_pm *pm, 173 | struct mt76_wcid *wcid, 174 | struct sk_buff *skb); 175 | void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, 176 | struct mt76_connac_pm *pm); 177 | 178 | #endif /* __MT76_CONNAC_H */ 179 | -------------------------------------------------------------------------------- /mt76_connac_mac.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #include "mt76_connac.h" 5 | 6 | int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) 7 | { 8 | struct mt76_dev *dev = phy->dev; 9 | 10 | if (!pm->enable) 11 | return 0; 12 | 13 | if (mt76_is_usb(dev)) 14 | return 0; 15 | 16 | cancel_delayed_work_sync(&pm->ps_work); 17 | if (!test_bit(MT76_STATE_PM, &phy->state)) 18 | return 0; 19 | 20 | if (pm->suspended) 21 | return 0; 22 | 23 | queue_work(dev->wq, &pm->wake_work); 24 | if (!wait_event_timeout(pm->wait, 25 | !test_bit(MT76_STATE_PM, &phy->state), 26 | 3 * HZ)) { 27 | ieee80211_wake_queues(phy->hw); 28 | return -ETIMEDOUT; 29 | } 30 | 31 | return 0; 32 | } 33 | EXPORT_SYMBOL_GPL(mt76_connac_pm_wake); 34 | 35 | void mt76_connac_power_save_sched(struct mt76_phy *phy, 36 | struct mt76_connac_pm *pm) 37 | { 38 | struct mt76_dev *dev = phy->dev; 39 | 40 | if (mt76_is_usb(dev)) 41 | return; 42 | 43 | if (!pm->enable) 44 | return; 45 | 46 | if (pm->suspended) 47 | return; 48 | 49 | pm->last_activity = jiffies; 50 | 51 | if (!test_bit(MT76_STATE_PM, &phy->state)) { 52 | cancel_delayed_work(&phy->mac_work); 53 | queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout); 54 | } 55 | } 56 | EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched); 57 | 58 | void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, 59 | struct mt76_wcid *wcid) 60 | { 61 | int i; 62 | 63 | spin_lock_bh(&pm->txq_lock); 64 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { 65 | if (wcid && pm->tx_q[i].wcid != wcid) 66 | continue; 67 | 68 | dev_kfree_skb(pm->tx_q[i].skb); 69 | pm->tx_q[i].skb = NULL; 70 | } 71 | spin_unlock_bh(&pm->txq_lock); 72 | } 73 | EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs); 74 | 75 | void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, 76 | struct mt76_connac_pm *pm, 77 | struct mt76_wcid *wcid, 78 | struct sk_buff *skb) 79 | { 80 | int qid = skb_get_queue_mapping(skb); 81 | struct mt76_phy *phy = hw->priv; 82 | 83 | spin_lock_bh(&pm->txq_lock); 84 | if (!pm->tx_q[qid].skb) { 85 | ieee80211_stop_queues(hw); 86 | pm->tx_q[qid].wcid = wcid; 87 | pm->tx_q[qid].skb = skb; 88 | queue_work(phy->dev->wq, &pm->wake_work); 89 | } else { 90 | dev_kfree_skb(skb); 91 | } 92 | spin_unlock_bh(&pm->txq_lock); 93 | } 94 | EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb); 95 | 96 | void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, 97 | struct mt76_connac_pm *pm) 98 | { 99 | int i; 100 | 101 | spin_lock_bh(&pm->txq_lock); 102 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { 103 | struct mt76_wcid *wcid = pm->tx_q[i].wcid; 104 | struct ieee80211_sta *sta = NULL; 105 | 106 | if (!pm->tx_q[i].skb) 107 | continue; 108 | 109 | if (wcid && wcid->sta) 110 | sta = container_of((void *)wcid, struct ieee80211_sta, 111 | drv_priv); 112 | 113 | mt76_tx(phy, sta, wcid, pm->tx_q[i].skb); 114 | pm->tx_q[i].skb = NULL; 115 | } 116 | spin_unlock_bh(&pm->txq_lock); 117 | 118 | mt76_worker_schedule(&phy->dev->tx_worker); 119 | } 120 | EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); 121 | -------------------------------------------------------------------------------- /mt76x0/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | obj-$(CONFIG_MT76x0U) += mt76x0u.o 3 | obj-$(CONFIG_MT76x0E) += mt76x0e.o 4 | obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o 5 | 6 | mt76x0-common-y := init.o main.o eeprom.o phy.o 7 | 8 | mt76x0u-y := usb.o usb_mcu.o 9 | mt76x0e-y := pci.o pci_mcu.o 10 | 11 | # ccflags-y := -DDEBUG 12 | -------------------------------------------------------------------------------- /mt76x0/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2014 Felix Fietkau 4 | * Copyright (C) 2015 Jakub Kicinski 5 | * Copyright (C) 2018 Stanislaw Gruszka 6 | */ 7 | 8 | #ifndef __MT76X0U_EEPROM_H 9 | #define __MT76X0U_EEPROM_H 10 | 11 | #include "../mt76x02_eeprom.h" 12 | 13 | struct mt76x02_dev; 14 | 15 | #define MT76X0U_EE_MAX_VER 0x0c 16 | #define MT76X0_EEPROM_SIZE 512 17 | 18 | int mt76x0_eeprom_init(struct mt76x02_dev *dev); 19 | void mt76x0_read_rx_gain(struct mt76x02_dev *dev); 20 | void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, 21 | struct ieee80211_channel *chan, 22 | struct mt76_rate_power *t); 23 | void mt76x0_get_power_info(struct mt76x02_dev *dev, 24 | struct ieee80211_channel *chan, s8 *tp); 25 | 26 | static inline s8 s6_to_s8(u32 val) 27 | { 28 | s8 ret = val & GENMASK(5, 0); 29 | 30 | if (ret & BIT(5)) 31 | ret -= BIT(6); 32 | return ret; 33 | } 34 | 35 | static inline bool mt76x0_tssi_enabled(struct mt76x02_dev *dev) 36 | { 37 | return (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & 38 | MT_EE_NIC_CONF_1_TX_ALC_EN); 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /mt76x0/initvals.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * (c) Copyright 2002-2010, Ralink Technology, Inc. 4 | * Copyright (C) 2015 Jakub Kicinski 5 | * Copyright (C) 2018 Stanislaw Gruszka 6 | * Copyright (C) 2018 Lorenzo Bianconi 7 | */ 8 | 9 | #ifndef __MT76X0U_INITVALS_H 10 | #define __MT76X0U_INITVALS_H 11 | 12 | #include "phy.h" 13 | 14 | static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = { 15 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } }, 16 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } }, 17 | 18 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 6), 0x00000045 } }, 19 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 6), 0x0000000A } }, 20 | 21 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 8), 0x16344EF0 } }, 22 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 8), 0x122C54F2 } }, 23 | 24 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 12), 0x05052879 } }, 25 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 12), 0x050528F9 } }, 26 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 12), 0x050528F9 } }, 27 | 28 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 13), 0x35050004 } }, 29 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 13), 0x2C3A0406 } }, 30 | 31 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 14), 0x310F2E3C } }, 32 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 14), 0x310F2A3F } }, 33 | 34 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 26), 0x007C2005 } }, 35 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 26), 0x007C2005 } }, 36 | 37 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 27), 0x000000E1 } }, 38 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 27), 0x000000EC } }, 39 | 40 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 28), 0x00060806 } }, 41 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00050806 } }, 42 | { RF_A_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00060801 } }, 43 | { RF_A_BAND | RF_BW_20 | RF_BW_80, { MT_BBP(AGC, 28), 0x00060806 } }, 44 | 45 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXO, 28), 0x0000008A } }, 46 | 47 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 31), 0x00000E23 } }, 48 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 31), 0x00000E13 } }, 49 | 50 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 32), 0x00003218 } }, 51 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 32), 0x0000181C } }, 52 | 53 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 33), 0x00003240 } }, 54 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 33), 0x00003218 } }, 55 | 56 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 35), 0x11111616 } }, 57 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 35), 0x11111516 } }, 58 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 35), 0x11111111 } }, 59 | 60 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 39), 0x2A2A3036 } }, 61 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 39), 0x2A2A2C36 } }, 62 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 39), 0x2A2A2A2A } }, 63 | 64 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 43), 0x27273438 } }, 65 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 43), 0x27272D38 } }, 66 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 43), 0x27271A1A } }, 67 | 68 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 51), 0x17171C1C } }, 69 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 51), 0xFFFFFFFF } }, 70 | 71 | { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 53), 0x26262A2F } }, 72 | { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 53), 0x2626322F } }, 73 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 53), 0xFFFFFFFF } }, 74 | 75 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 55), 0x40404040 } }, 76 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 55), 0xFFFFFFFF } }, 77 | 78 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 58), 0x00001010 } }, 79 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 58), 0x00000000 } }, 80 | 81 | { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(RXFE, 0), 0x3D5000E0 } }, 82 | { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } }, 83 | }; 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /mt76x0/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2014 Felix Fietkau 4 | * Copyright (C) 2015 Jakub Kicinski 5 | * Copyright (C) 2018 Stanislaw Gruszka 6 | */ 7 | 8 | #include 9 | #include "mt76x0.h" 10 | 11 | static void 12 | mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) 13 | { 14 | cancel_delayed_work_sync(&dev->cal_work); 15 | mt76x02_pre_tbtt_enable(dev, false); 16 | if (mt76_is_mmio(&dev->mt76)) 17 | tasklet_disable(&dev->dfs_pd.dfs_tasklet); 18 | 19 | mt76_set_channel(&dev->mphy); 20 | mt76x0_phy_set_channel(dev, chandef); 21 | 22 | mt76x02_mac_cc_reset(dev); 23 | mt76x02_edcca_init(dev); 24 | 25 | if (mt76_is_mmio(&dev->mt76)) { 26 | mt76x02_dfs_init_params(dev); 27 | tasklet_enable(&dev->dfs_pd.dfs_tasklet); 28 | } 29 | mt76x02_pre_tbtt_enable(dev, true); 30 | 31 | mt76_txq_schedule_all(&dev->mphy); 32 | } 33 | 34 | int mt76x0_set_sar_specs(struct ieee80211_hw *hw, 35 | const struct cfg80211_sar_specs *sar) 36 | { 37 | int err = -EINVAL, power = hw->conf.power_level * 2; 38 | struct mt76x02_dev *dev = hw->priv; 39 | struct mt76_phy *mphy = &dev->mphy; 40 | 41 | mutex_lock(&dev->mt76.mutex); 42 | if (!cfg80211_chandef_valid(&mphy->chandef)) 43 | goto out; 44 | 45 | err = mt76_init_sar_power(hw, sar); 46 | if (err) 47 | goto out; 48 | 49 | dev->txpower_conf = mt76_get_sar_power(mphy, mphy->chandef.chan, 50 | power); 51 | if (test_bit(MT76_STATE_RUNNING, &mphy->state)) 52 | mt76x0_phy_set_txpower(dev); 53 | out: 54 | mutex_unlock(&dev->mt76.mutex); 55 | 56 | return err; 57 | } 58 | EXPORT_SYMBOL_GPL(mt76x0_set_sar_specs); 59 | 60 | int mt76x0_config(struct ieee80211_hw *hw, u32 changed) 61 | { 62 | struct mt76x02_dev *dev = hw->priv; 63 | 64 | mutex_lock(&dev->mt76.mutex); 65 | 66 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 67 | ieee80211_stop_queues(hw); 68 | mt76x0_set_channel(dev, &hw->conf.chandef); 69 | ieee80211_wake_queues(hw); 70 | } 71 | 72 | if (changed & IEEE80211_CONF_CHANGE_POWER) { 73 | struct mt76_phy *mphy = &dev->mphy; 74 | 75 | dev->txpower_conf = hw->conf.power_level * 2; 76 | dev->txpower_conf = mt76_get_sar_power(mphy, 77 | mphy->chandef.chan, 78 | dev->txpower_conf); 79 | if (test_bit(MT76_STATE_RUNNING, &mphy->state)) 80 | mt76x0_phy_set_txpower(dev); 81 | } 82 | 83 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 84 | if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) 85 | dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; 86 | else 87 | dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; 88 | 89 | mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 90 | } 91 | 92 | mutex_unlock(&dev->mt76.mutex); 93 | 94 | return 0; 95 | } 96 | EXPORT_SYMBOL_GPL(mt76x0_config); 97 | -------------------------------------------------------------------------------- /mt76x0/mcu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2014 Felix Fietkau 4 | * Copyright (C) 2015 Jakub Kicinski 5 | */ 6 | 7 | #ifndef __MT76X0U_MCU_H 8 | #define __MT76X0U_MCU_H 9 | 10 | #include "../mt76x02_mcu.h" 11 | 12 | struct mt76x02_dev; 13 | 14 | #define MT_MCU_IVB_SIZE 0x40 15 | #define MT_MCU_DLM_OFFSET 0x80000 16 | 17 | /* We use same space for BBP as for MAC regs 18 | * #define MT_MCU_MEMMAP_BBP 0x40000000 19 | */ 20 | #define MT_MCU_MEMMAP_RF 0x80000000 21 | 22 | enum mcu_calibrate { 23 | MCU_CAL_R = 1, 24 | MCU_CAL_RXDCOC, 25 | MCU_CAL_LC, 26 | MCU_CAL_LOFT, 27 | MCU_CAL_TXIQ, 28 | MCU_CAL_BW, 29 | MCU_CAL_DPD, 30 | MCU_CAL_RXIQ, 31 | MCU_CAL_TXDCOC, 32 | MCU_CAL_RX_GROUP_DELAY, 33 | MCU_CAL_TX_GROUP_DELAY, 34 | MCU_CAL_VCO, 35 | MCU_CAL_NO_SIGNAL = 0xfe, 36 | MCU_CAL_FULL = 0xff, 37 | }; 38 | 39 | int mt76x0e_mcu_init(struct mt76x02_dev *dev); 40 | int mt76x0u_mcu_init(struct mt76x02_dev *dev); 41 | static inline int mt76x0_firmware_running(struct mt76x02_dev *dev) 42 | { 43 | return mt76_rr(dev, MT_MCU_COM_REG0) == 1; 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /mt76x0/mt76x0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2014 Felix Fietkau 4 | * Copyright (C) 2015 Jakub Kicinski 5 | * Copyright (C) 2018 Stanislaw Gruszka 6 | */ 7 | 8 | #ifndef MT76X0U_H 9 | #define MT76X0U_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "../mt76x02.h" 21 | #include "eeprom.h" 22 | 23 | #define MT7610E_FIRMWARE "mediatek/mt7610e.bin" 24 | #define MT7650E_FIRMWARE "mediatek/mt7650e.bin" 25 | 26 | #define MT7610U_FIRMWARE "mediatek/mt7610u.bin" 27 | 28 | #define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */ 29 | #define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ 30 | 31 | static inline bool is_mt7610e(struct mt76x02_dev *dev) 32 | { 33 | if (!mt76_is_mmio(&dev->mt76)) 34 | return false; 35 | 36 | return mt76_chip(&dev->mt76) == 0x7610; 37 | } 38 | 39 | static inline bool is_mt7630(struct mt76x02_dev *dev) 40 | { 41 | return mt76_chip(&dev->mt76) == 0x7630; 42 | } 43 | 44 | /* Init */ 45 | int mt76x0_init_hardware(struct mt76x02_dev *dev); 46 | int mt76x0_register_device(struct mt76x02_dev *dev); 47 | void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); 48 | 49 | void mt76x0_mac_stop(struct mt76x02_dev *dev); 50 | 51 | int mt76x0_config(struct ieee80211_hw *hw, u32 changed); 52 | int mt76x0_set_sar_specs(struct ieee80211_hw *hw, 53 | const struct cfg80211_sar_specs *sar); 54 | 55 | /* PHY */ 56 | void mt76x0_phy_init(struct mt76x02_dev *dev); 57 | int mt76x0_phy_wait_bbp_ready(struct mt76x02_dev *dev); 58 | void mt76x0_phy_set_channel(struct mt76x02_dev *dev, 59 | struct cfg80211_chan_def *chandef); 60 | void mt76x0_phy_set_txpower(struct mt76x02_dev *dev); 61 | void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on); 62 | #endif 63 | -------------------------------------------------------------------------------- /mt76x0/pci_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | #include 6 | #include 7 | 8 | #include "mt76x0.h" 9 | #include "mcu.h" 10 | 11 | #define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE) 12 | 13 | static int mt76x0e_load_firmware(struct mt76x02_dev *dev) 14 | { 15 | bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610; 16 | u32 val, ilm_len, dlm_len, offset = 0; 17 | const struct mt76x02_fw_header *hdr; 18 | const struct firmware *fw; 19 | const char *firmware; 20 | const u8 *fw_payload; 21 | int len, err; 22 | 23 | if (is_combo_chip) 24 | firmware = MT7650E_FIRMWARE; 25 | else 26 | firmware = MT7610E_FIRMWARE; 27 | 28 | err = request_firmware(&fw, firmware, dev->mt76.dev); 29 | if (err) 30 | return err; 31 | 32 | if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 33 | err = -EIO; 34 | goto out; 35 | } 36 | 37 | hdr = (const struct mt76x02_fw_header *)fw->data; 38 | 39 | len = sizeof(*hdr); 40 | len += le32_to_cpu(hdr->ilm_len); 41 | len += le32_to_cpu(hdr->dlm_len); 42 | 43 | if (fw->size != len) { 44 | err = -EIO; 45 | goto out; 46 | } 47 | 48 | fw_payload = fw->data + sizeof(*hdr); 49 | 50 | val = le16_to_cpu(hdr->fw_ver); 51 | dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", 52 | (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); 53 | 54 | val = le16_to_cpu(hdr->fw_ver); 55 | dev_dbg(dev->mt76.dev, 56 | "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", 57 | (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, 58 | le16_to_cpu(hdr->build_ver), hdr->build_time); 59 | 60 | if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) { 61 | dev_err(dev->mt76.dev, 62 | "Could not get hardware semaphore for loading fw\n"); 63 | err = -ETIMEDOUT; 64 | goto out; 65 | } 66 | 67 | /* upload ILM. */ 68 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); 69 | ilm_len = le32_to_cpu(hdr->ilm_len); 70 | if (is_combo_chip) { 71 | ilm_len -= MT_MCU_IVB_SIZE; 72 | offset = MT_MCU_IVB_SIZE; 73 | } 74 | dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len); 75 | mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset, 76 | ilm_len); 77 | 78 | /* upload IVB. */ 79 | if (is_combo_chip) { 80 | dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n", 81 | MT_MCU_IVB_SIZE); 82 | mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE); 83 | } 84 | 85 | /* upload DLM. */ 86 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); 87 | dlm_len = le32_to_cpu(hdr->dlm_len); 88 | dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); 89 | mt76_wr_copy(dev, MT_MCU_ILM_ADDR, 90 | fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len); 91 | 92 | /* trigger firmware */ 93 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); 94 | if (is_combo_chip) 95 | mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3); 96 | else 97 | mt76_wr(dev, MT_MCU_RESET_CTL, 0x300); 98 | 99 | if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { 100 | dev_err(dev->mt76.dev, "Firmware failed to start\n"); 101 | err = -ETIMEDOUT; 102 | goto out; 103 | } 104 | 105 | mt76x02_set_ethtool_fwver(dev, hdr); 106 | dev_dbg(dev->mt76.dev, "Firmware running!\n"); 107 | 108 | out: 109 | if (is_combo_chip) 110 | mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1); 111 | release_firmware(fw); 112 | 113 | return err; 114 | } 115 | 116 | int mt76x0e_mcu_init(struct mt76x02_dev *dev) 117 | { 118 | static const struct mt76_mcu_ops mt76x0e_mcu_ops = { 119 | .mcu_send_msg = mt76x02_mcu_msg_send, 120 | .mcu_parse_response = mt76x02_mcu_parse_response, 121 | }; 122 | int err; 123 | 124 | dev->mt76.mcu_ops = &mt76x0e_mcu_ops; 125 | 126 | err = mt76x0e_load_firmware(dev); 127 | if (err < 0) 128 | return err; 129 | 130 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /mt76x0/phy.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * (c) Copyright 2002-2010, Ralink Technology, Inc. 4 | * Copyright (C) 2018 Stanislaw Gruszka 5 | */ 6 | #ifndef _MT76X0_PHY_H_ 7 | #define _MT76X0_PHY_H_ 8 | 9 | #define RF_G_BAND 0x0100 10 | #define RF_A_BAND 0x0200 11 | #define RF_A_BAND_LB 0x0400 12 | #define RF_A_BAND_MB 0x0800 13 | #define RF_A_BAND_HB 0x1000 14 | #define RF_A_BAND_11J 0x2000 15 | 16 | #define RF_BW_20 1 17 | #define RF_BW_40 2 18 | #define RF_BW_10 4 19 | #define RF_BW_80 8 20 | 21 | #define MT_RF(bank, reg) ((bank) << 16 | (reg)) 22 | #define MT_RF_BANK(offset) ((offset) >> 16) 23 | #define MT_RF_REG(offset) ((offset) & 0xff) 24 | 25 | #define MT_RF_VCO_BP_CLOSE_LOOP BIT(3) 26 | #define MT_RF_VCO_BP_CLOSE_LOOP_MASK GENMASK(3, 0) 27 | #define MT_RF_VCO_CAL_MASK GENMASK(2, 0) 28 | #define MT_RF_START_TIME 0x3 29 | #define MT_RF_START_TIME_MASK GENMASK(2, 0) 30 | #define MT_RF_SETTLE_TIME_MASK GENMASK(6, 4) 31 | 32 | #define MT_RF_PLL_DEN_MASK GENMASK(4, 0) 33 | #define MT_RF_PLL_K_MASK GENMASK(4, 0) 34 | #define MT_RF_SDM_RESET_MASK BIT(7) 35 | #define MT_RF_SDM_MASH_PRBS_MASK GENMASK(6, 2) 36 | #define MT_RF_SDM_BP_MASK BIT(1) 37 | #define MT_RF_ISI_ISO_MASK GENMASK(7, 6) 38 | #define MT_RF_PFD_DLY_MASK GENMASK(5, 4) 39 | #define MT_RF_CLK_SEL_MASK GENMASK(3, 2) 40 | #define MT_RF_XO_DIV_MASK GENMASK(1, 0) 41 | 42 | struct mt76x0_bbp_switch_item { 43 | u16 bw_band; 44 | struct mt76_reg_pair reg_pair; 45 | }; 46 | 47 | struct mt76x0_rf_switch_item { 48 | u32 rf_bank_reg; 49 | u16 bw_band; 50 | u8 value; 51 | }; 52 | 53 | struct mt76x0_freq_item { 54 | u8 channel; 55 | u32 band; 56 | u8 pllR37; 57 | u8 pllR36; 58 | u8 pllR35; 59 | u8 pllR34; 60 | u8 pllR33; 61 | u8 pllR32_b7b5; 62 | u8 pllR32_b4b0; /* PLL_DEN (Denomina - 8) */ 63 | u8 pllR31_b7b5; 64 | u8 pllR31_b4b0; /* PLL_K (Nominator *)*/ 65 | u8 pllR30_b7; /* sdm_reset_n */ 66 | u8 pllR30_b6b2; /* sdmmash_prbs,sin */ 67 | u8 pllR30_b1; /* sdm_bp */ 68 | u16 pll_n; /* R30<0>, R29<7:0> (hex) */ 69 | u8 pllR28_b7b6; /* isi,iso */ 70 | u8 pllR28_b5b4; /* pfd_dly */ 71 | u8 pllR28_b3b2; /* clksel option */ 72 | u32 pll_sdm_k; /* R28<1:0>, R27<7:0>, R26<7:0> (hex) SDM_k */ 73 | u8 pllR24_b1b0; /* xo_div */ 74 | }; 75 | 76 | struct mt76x0_rate_pwr_item { 77 | s8 mcs_power; 78 | u8 rf_pa_mode; 79 | }; 80 | 81 | struct mt76x0_rate_pwr_tab { 82 | struct mt76x0_rate_pwr_item cck[4]; 83 | struct mt76x0_rate_pwr_item ofdm[8]; 84 | struct mt76x0_rate_pwr_item ht[8]; 85 | struct mt76x0_rate_pwr_item vht[10]; 86 | struct mt76x0_rate_pwr_item stbc[8]; 87 | struct mt76x0_rate_pwr_item mcs32; 88 | }; 89 | 90 | #endif /* _MT76X0_PHY_H_ */ 91 | -------------------------------------------------------------------------------- /mt76x0/usb_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mt76x0.h" 10 | #include "mcu.h" 11 | #include "../mt76x02_usb.h" 12 | 13 | #define MCU_FW_URB_MAX_PAYLOAD 0x38f8 14 | #define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) 15 | 16 | static int 17 | mt76x0u_upload_firmware(struct mt76x02_dev *dev, 18 | const struct mt76x02_fw_header *hdr) 19 | { 20 | u8 *fw_payload = (u8 *)(hdr + 1); 21 | u32 ilm_len, dlm_len; 22 | void *ivb; 23 | int err; 24 | 25 | ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); 26 | if (!ivb) 27 | return -ENOMEM; 28 | 29 | ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; 30 | dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", 31 | ilm_len, MT_MCU_IVB_SIZE); 32 | err = mt76x02u_mcu_fw_send_data(dev, fw_payload + MT_MCU_IVB_SIZE, 33 | ilm_len, MCU_FW_URB_MAX_PAYLOAD, 34 | MT_MCU_IVB_SIZE); 35 | if (err) 36 | goto out; 37 | 38 | dlm_len = le32_to_cpu(hdr->dlm_len); 39 | dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); 40 | err = mt76x02u_mcu_fw_send_data(dev, 41 | fw_payload + le32_to_cpu(hdr->ilm_len), 42 | dlm_len, MCU_FW_URB_MAX_PAYLOAD, 43 | MT_MCU_DLM_OFFSET); 44 | if (err) 45 | goto out; 46 | 47 | err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, 48 | USB_DIR_OUT | USB_TYPE_VENDOR, 49 | 0x12, 0, ivb, MT_MCU_IVB_SIZE); 50 | if (err < 0) 51 | goto out; 52 | 53 | if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { 54 | dev_err(dev->mt76.dev, "Firmware failed to start\n"); 55 | err = -ETIMEDOUT; 56 | goto out; 57 | } 58 | 59 | dev_dbg(dev->mt76.dev, "Firmware running!\n"); 60 | 61 | out: 62 | kfree(ivb); 63 | 64 | return err; 65 | } 66 | 67 | static int mt76x0_get_firmware(struct mt76x02_dev *dev, 68 | const struct firmware **fw) 69 | { 70 | int err; 71 | 72 | /* try to load mt7610e fw if available 73 | * otherwise fall back to mt7610u one 74 | */ 75 | err = firmware_request_nowarn(fw, MT7610E_FIRMWARE, dev->mt76.dev); 76 | if (err) { 77 | dev_info(dev->mt76.dev, "%s not found, switching to %s", 78 | MT7610E_FIRMWARE, MT7610U_FIRMWARE); 79 | return request_firmware(fw, MT7610U_FIRMWARE, 80 | dev->mt76.dev); 81 | } 82 | return 0; 83 | } 84 | 85 | static int mt76x0u_load_firmware(struct mt76x02_dev *dev) 86 | { 87 | const struct firmware *fw; 88 | const struct mt76x02_fw_header *hdr; 89 | int len, ret; 90 | u32 val; 91 | 92 | mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | 93 | MT_USB_DMA_CFG_TX_BULK_EN)); 94 | 95 | if (mt76x0_firmware_running(dev)) 96 | return 0; 97 | 98 | ret = mt76x0_get_firmware(dev, &fw); 99 | if (ret) 100 | return ret; 101 | 102 | if (!fw || !fw->data || fw->size < sizeof(*hdr)) 103 | goto err_inv_fw; 104 | 105 | hdr = (const struct mt76x02_fw_header *)fw->data; 106 | 107 | if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) 108 | goto err_inv_fw; 109 | 110 | len = sizeof(*hdr); 111 | len += le32_to_cpu(hdr->ilm_len); 112 | len += le32_to_cpu(hdr->dlm_len); 113 | 114 | if (fw->size != len) 115 | goto err_inv_fw; 116 | 117 | val = le16_to_cpu(hdr->fw_ver); 118 | dev_dbg(dev->mt76.dev, 119 | "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", 120 | (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, 121 | le16_to_cpu(hdr->build_ver), hdr->build_time); 122 | 123 | len = le32_to_cpu(hdr->ilm_len); 124 | 125 | mt76_wr(dev, 0x1004, 0x2c); 126 | 127 | mt76_set(dev, MT_USB_DMA_CFG, 128 | (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | 129 | FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); 130 | mt76x02u_mcu_fw_reset(dev); 131 | usleep_range(5000, 6000); 132 | 133 | mt76_wr(dev, MT_FCE_PSE_CTRL, 1); 134 | 135 | /* FCE tx_fs_base_ptr */ 136 | mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); 137 | /* FCE tx_fs_max_cnt */ 138 | mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); 139 | /* FCE pdma enable */ 140 | mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); 141 | /* FCE skip_fs_en */ 142 | mt76_wr(dev, MT_FCE_SKIP_FS, 3); 143 | 144 | val = mt76_rr(dev, MT_USB_DMA_CFG); 145 | val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; 146 | mt76_wr(dev, MT_USB_DMA_CFG, val); 147 | val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; 148 | mt76_wr(dev, MT_USB_DMA_CFG, val); 149 | 150 | ret = mt76x0u_upload_firmware(dev, hdr); 151 | release_firmware(fw); 152 | 153 | mt76_wr(dev, MT_FCE_PSE_CTRL, 1); 154 | 155 | return ret; 156 | 157 | err_inv_fw: 158 | dev_err(dev->mt76.dev, "Invalid firmware image\n"); 159 | release_firmware(fw); 160 | return -ENOENT; 161 | } 162 | 163 | int mt76x0u_mcu_init(struct mt76x02_dev *dev) 164 | { 165 | int ret; 166 | 167 | ret = mt76x0u_load_firmware(dev); 168 | if (ret < 0) 169 | return ret; 170 | 171 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 172 | 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /mt76x02_debugfs.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | #include "mt76x02.h" 8 | 9 | static int 10 | mt76x02_ampdu_stat_show(struct seq_file *file, void *data) 11 | { 12 | struct mt76x02_dev *dev = file->private; 13 | int i, j; 14 | 15 | for (i = 0; i < 4; i++) { 16 | seq_puts(file, "Length: "); 17 | for (j = 0; j < 8; j++) 18 | seq_printf(file, "%8d | ", i * 8 + j + 1); 19 | seq_puts(file, "\n"); 20 | seq_puts(file, "Count: "); 21 | for (j = 0; j < 8; j++) 22 | seq_printf(file, "%8d | ", 23 | dev->mt76.aggr_stats[i * 8 + j]); 24 | seq_puts(file, "\n"); 25 | seq_puts(file, "--------"); 26 | for (j = 0; j < 8; j++) 27 | seq_puts(file, "-----------"); 28 | seq_puts(file, "\n"); 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | DEFINE_SHOW_ATTRIBUTE(mt76x02_ampdu_stat); 35 | 36 | static int read_txpower(struct seq_file *file, void *data) 37 | { 38 | struct mt76x02_dev *dev = dev_get_drvdata(file->private); 39 | 40 | seq_printf(file, "Target power: %d\n", dev->target_power); 41 | 42 | mt76_seq_puts_array(file, "Delta", dev->target_power_delta, 43 | ARRAY_SIZE(dev->target_power_delta)); 44 | return 0; 45 | } 46 | 47 | static int 48 | mt76x02_dfs_stat_show(struct seq_file *file, void *data) 49 | { 50 | struct mt76x02_dev *dev = file->private; 51 | struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 52 | int i; 53 | 54 | seq_printf(file, "allocated sequences:\t%d\n", 55 | dfs_pd->seq_stats.seq_pool_len); 56 | seq_printf(file, "used sequences:\t\t%d\n", 57 | dfs_pd->seq_stats.seq_len); 58 | seq_puts(file, "\n"); 59 | 60 | for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { 61 | seq_printf(file, "engine: %d\n", i); 62 | seq_printf(file, " hw pattern detected:\t%d\n", 63 | dfs_pd->stats[i].hw_pattern); 64 | seq_printf(file, " hw pulse discarded:\t%d\n", 65 | dfs_pd->stats[i].hw_pulse_discarded); 66 | seq_printf(file, " sw pattern detected:\t%d\n", 67 | dfs_pd->stats[i].sw_pattern); 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | DEFINE_SHOW_ATTRIBUTE(mt76x02_dfs_stat); 74 | 75 | static int read_agc(struct seq_file *file, void *data) 76 | { 77 | struct mt76x02_dev *dev = dev_get_drvdata(file->private); 78 | 79 | seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); 80 | seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); 81 | seq_printf(file, "false_cca: %d\n", dev->cal.false_cca); 82 | seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust); 83 | 84 | return 0; 85 | } 86 | 87 | static int 88 | mt76_edcca_set(void *data, u64 val) 89 | { 90 | struct mt76x02_dev *dev = data; 91 | enum nl80211_dfs_regions region = dev->mt76.region; 92 | 93 | mutex_lock(&dev->mt76.mutex); 94 | 95 | dev->ed_monitor_enabled = !!val; 96 | dev->ed_monitor = dev->ed_monitor_enabled && 97 | region == NL80211_DFS_ETSI; 98 | mt76x02_edcca_init(dev); 99 | 100 | mutex_unlock(&dev->mt76.mutex); 101 | 102 | return 0; 103 | } 104 | 105 | static int 106 | mt76_edcca_get(void *data, u64 *val) 107 | { 108 | struct mt76x02_dev *dev = data; 109 | 110 | *val = dev->ed_monitor_enabled; 111 | return 0; 112 | } 113 | 114 | DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt76_edcca_get, mt76_edcca_set, 115 | "%lld\n"); 116 | 117 | void mt76x02_init_debugfs(struct mt76x02_dev *dev) 118 | { 119 | struct dentry *dir; 120 | 121 | dir = mt76_register_debugfs(&dev->mt76); 122 | if (!dir) 123 | return; 124 | 125 | debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, 126 | mt76_queues_read); 127 | debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); 128 | debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); 129 | 130 | debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); 131 | debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt76x02_ampdu_stat_fops); 132 | debugfs_create_file("dfs_stats", 0400, dir, dev, &mt76x02_dfs_stat_fops); 133 | debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, 134 | read_txpower); 135 | 136 | debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); 137 | 138 | debugfs_create_u32("tx_hang_reset", 0400, dir, &dev->tx_hang_reset); 139 | } 140 | EXPORT_SYMBOL_GPL(mt76x02_init_debugfs); 141 | -------------------------------------------------------------------------------- /mt76x02_dfs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x02_DFS_H 7 | #define __MT76x02_DFS_H 8 | 9 | #include 10 | #include 11 | 12 | #define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ 13 | #define MT_DFS_NUM_ENGINES 4 14 | 15 | /* bbp params */ 16 | #define MT_DFS_SYM_ROUND 0 17 | #define MT_DFS_DELTA_DELAY 2 18 | #define MT_DFS_VGA_MASK 0 19 | #define MT_DFS_PWR_GAIN_OFFSET 3 20 | #define MT_DFS_PWR_DOWN_TIME 0xf 21 | #define MT_DFS_RX_PE_MASK 0xff 22 | #define MT_DFS_PKT_END_MASK 0 23 | #define MT_DFS_CH_EN 0xf 24 | 25 | /* sw detector params */ 26 | #define MT_DFS_EVENT_LOOP 64 27 | #define MT_DFS_SW_TIMEOUT (HZ / 20) 28 | #define MT_DFS_EVENT_WINDOW (HZ / 5) 29 | #define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) 30 | #define MT_DFS_EVENT_TIME_MARGIN 2000 31 | #define MT_DFS_PRI_MARGIN 4 32 | #define MT_DFS_SEQUENCE_TH 6 33 | 34 | #define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) 35 | #define MT_DFS_FCC_MIN_PRI (3000 - 2) 36 | #define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) 37 | #define MT_DFS_JP_MIN_PRI (28500 - 2) 38 | #define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) 39 | #define MT_DFS_ETSI_MIN_PRI (4500 - 20) 40 | 41 | struct mt76x02_radar_specs { 42 | u8 mode; 43 | u16 avg_len; 44 | u16 e_low; 45 | u16 e_high; 46 | u16 w_low; 47 | u16 w_high; 48 | u16 w_margin; 49 | u32 t_low; 50 | u32 t_high; 51 | u16 t_margin; 52 | u32 b_low; 53 | u32 b_high; 54 | u32 event_expiration; 55 | u16 pwr_jmp; 56 | }; 57 | 58 | #define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) 59 | #define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) 60 | #define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) 61 | #define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) 62 | struct mt76x02_dfs_event { 63 | unsigned long fetch_ts; 64 | u32 ts; 65 | u16 width; 66 | u8 engine; 67 | }; 68 | 69 | #define MT_DFS_EVENT_BUFLEN 256 70 | struct mt76x02_dfs_event_rb { 71 | struct mt76x02_dfs_event data[MT_DFS_EVENT_BUFLEN]; 72 | int h_rb, t_rb; 73 | }; 74 | 75 | struct mt76x02_dfs_sequence { 76 | struct list_head head; 77 | u32 first_ts; 78 | u32 last_ts; 79 | u32 pri; 80 | u16 count; 81 | u8 engine; 82 | }; 83 | 84 | struct mt76x02_dfs_hw_pulse { 85 | u8 engine; 86 | u32 period; 87 | u32 w1; 88 | u32 w2; 89 | u32 burst; 90 | }; 91 | 92 | struct mt76x02_dfs_sw_detector_params { 93 | u32 min_pri; 94 | u32 max_pri; 95 | u32 pri_margin; 96 | }; 97 | 98 | struct mt76x02_dfs_engine_stats { 99 | u32 hw_pattern; 100 | u32 hw_pulse_discarded; 101 | u32 sw_pattern; 102 | }; 103 | 104 | struct mt76x02_dfs_seq_stats { 105 | u32 seq_pool_len; 106 | u32 seq_len; 107 | }; 108 | 109 | struct mt76x02_dfs_pattern_detector { 110 | u8 chirp_pulse_cnt; 111 | u32 chirp_pulse_ts; 112 | 113 | struct mt76x02_dfs_sw_detector_params sw_dpd_params; 114 | struct mt76x02_dfs_event_rb event_rb[2]; 115 | 116 | struct list_head sequences; 117 | struct list_head seq_pool; 118 | struct mt76x02_dfs_seq_stats seq_stats; 119 | 120 | unsigned long last_sw_check; 121 | u32 last_event_ts; 122 | 123 | struct mt76x02_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; 124 | struct tasklet_struct dfs_tasklet; 125 | }; 126 | 127 | void mt76x02_dfs_init_params(struct mt76x02_dev *dev); 128 | void mt76x02_dfs_init_detector(struct mt76x02_dev *dev); 129 | void mt76x02_regd_notifier(struct wiphy *wiphy, 130 | struct regulatory_request *request); 131 | void mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev *dev); 132 | #endif /* __MT76x02_DFS_H */ 133 | -------------------------------------------------------------------------------- /mt76x02_dma.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x02_DMA_H 7 | #define __MT76x02_DMA_H 8 | 9 | #include "mt76x02.h" 10 | #include "dma.h" 11 | 12 | #define MT_TXD_INFO_LEN GENMASK(15, 0) 13 | #define MT_TXD_INFO_NEXT_VLD BIT(16) 14 | #define MT_TXD_INFO_TX_BURST BIT(17) 15 | #define MT_TXD_INFO_80211 BIT(19) 16 | #define MT_TXD_INFO_TSO BIT(20) 17 | #define MT_TXD_INFO_CSO BIT(21) 18 | #define MT_TXD_INFO_WIV BIT(24) 19 | #define MT_TXD_INFO_QSEL GENMASK(26, 25) 20 | #define MT_TXD_INFO_DPORT GENMASK(29, 27) 21 | #define MT_TXD_INFO_TYPE GENMASK(31, 30) 22 | 23 | #define MT_RX_FCE_INFO_LEN GENMASK(13, 0) 24 | #define MT_RX_FCE_INFO_SELF_GEN BIT(15) 25 | #define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16) 26 | #define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20) 27 | #define MT_RX_FCE_INFO_PCIE_INTR BIT(24) 28 | #define MT_RX_FCE_INFO_QSEL GENMASK(26, 25) 29 | #define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27) 30 | #define MT_RX_FCE_INFO_TYPE GENMASK(31, 30) 31 | 32 | /* MCU request message header */ 33 | #define MT_MCU_MSG_LEN GENMASK(15, 0) 34 | #define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16) 35 | #define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20) 36 | #define MT_MCU_MSG_PORT GENMASK(29, 27) 37 | #define MT_MCU_MSG_TYPE GENMASK(31, 30) 38 | #define MT_MCU_MSG_TYPE_CMD BIT(30) 39 | 40 | #define MT_RX_HEADROOM 32 41 | #define MT76X02_RX_RING_SIZE 256 42 | 43 | enum dma_msg_port { 44 | WLAN_PORT, 45 | CPU_RX_PORT, 46 | CPU_TX_PORT, 47 | HOST_PORT, 48 | VIRTUAL_CPU_RX_PORT, 49 | VIRTUAL_CPU_TX_PORT, 50 | DISCARD, 51 | }; 52 | 53 | static inline bool 54 | mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) 55 | { 56 | return __mt76_poll(dev, MT_WPDMA_GLO_CFG, 57 | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 58 | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 59 | 0, timeout); 60 | } 61 | 62 | int mt76x02_dma_init(struct mt76x02_dev *dev); 63 | void mt76x02_dma_disable(struct mt76x02_dev *dev); 64 | 65 | #endif /* __MT76x02_DMA_H */ 66 | -------------------------------------------------------------------------------- /mt76x02_eeprom.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | * Copyright (C) 2018 Lorenzo Bianconi 5 | */ 6 | 7 | #include 8 | 9 | #include "mt76x02_eeprom.h" 10 | 11 | static int 12 | mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data, 13 | enum mt76x02_eeprom_modes mode) 14 | { 15 | u32 val; 16 | int i; 17 | 18 | val = mt76_rr(dev, MT_EFUSE_CTRL); 19 | val &= ~(MT_EFUSE_CTRL_AIN | 20 | MT_EFUSE_CTRL_MODE); 21 | val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); 22 | val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); 23 | val |= MT_EFUSE_CTRL_KICK; 24 | mt76_wr(dev, MT_EFUSE_CTRL, val); 25 | 26 | if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 27 | return -ETIMEDOUT; 28 | 29 | udelay(2); 30 | 31 | val = mt76_rr(dev, MT_EFUSE_CTRL); 32 | if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 33 | memset(data, 0xff, 16); 34 | return 0; 35 | } 36 | 37 | for (i = 0; i < 4; i++) { 38 | val = mt76_rr(dev, MT_EFUSE_DATA(i)); 39 | put_unaligned_le32(val, data + 4 * i); 40 | } 41 | 42 | return 0; 43 | } 44 | 45 | int mt76x02_eeprom_copy(struct mt76x02_dev *dev, 46 | enum mt76x02_eeprom_field field, 47 | void *dest, int len) 48 | { 49 | if (field + len > dev->mt76.eeprom.size) 50 | return -1; 51 | 52 | memcpy(dest, dev->mt76.eeprom.data + field, len); 53 | return 0; 54 | } 55 | EXPORT_SYMBOL_GPL(mt76x02_eeprom_copy); 56 | 57 | int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, 58 | int len, enum mt76x02_eeprom_modes mode) 59 | { 60 | int ret, i; 61 | 62 | for (i = 0; i + 16 <= len; i += 16) { 63 | ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); 64 | if (ret) 65 | return ret; 66 | } 67 | 68 | return 0; 69 | } 70 | EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); 71 | 72 | void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) 73 | { 74 | u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 75 | 76 | switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { 77 | case BOARD_TYPE_5GHZ: 78 | dev->mphy.cap.has_5ghz = true; 79 | break; 80 | case BOARD_TYPE_2GHZ: 81 | dev->mphy.cap.has_2ghz = true; 82 | break; 83 | default: 84 | dev->mphy.cap.has_2ghz = true; 85 | dev->mphy.cap.has_5ghz = true; 86 | break; 87 | } 88 | } 89 | EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); 90 | 91 | bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) 92 | { 93 | u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 94 | 95 | if (band == NL80211_BAND_5GHZ) 96 | return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); 97 | else 98 | return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); 99 | } 100 | EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); 101 | 102 | void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, 103 | u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) 104 | { 105 | u16 val; 106 | 107 | val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); 108 | *lna_2g = val & 0xff; 109 | lna_5g[0] = val >> 8; 110 | 111 | val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); 112 | lna_5g[1] = val >> 8; 113 | 114 | val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); 115 | lna_5g[2] = val >> 8; 116 | 117 | if (!mt76x02_field_valid(lna_5g[1])) 118 | lna_5g[1] = lna_5g[0]; 119 | 120 | if (!mt76x02_field_valid(lna_5g[2])) 121 | lna_5g[2] = lna_5g[0]; 122 | 123 | if (band == NL80211_BAND_2GHZ) 124 | *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); 125 | else 126 | *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); 127 | } 128 | EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); 129 | 130 | u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, 131 | s8 *lna_2g, s8 *lna_5g, 132 | struct ieee80211_channel *chan) 133 | { 134 | u16 val; 135 | u8 lna; 136 | 137 | val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 138 | if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) 139 | *lna_2g = 0; 140 | if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) 141 | memset(lna_5g, 0, sizeof(s8) * 3); 142 | 143 | if (chan->band == NL80211_BAND_2GHZ) 144 | lna = *lna_2g; 145 | else if (chan->hw_value <= 64) 146 | lna = lna_5g[0]; 147 | else if (chan->hw_value <= 128) 148 | lna = lna_5g[1]; 149 | else 150 | lna = lna_5g[2]; 151 | 152 | return lna != 0xff ? lna : 0; 153 | } 154 | EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); 155 | -------------------------------------------------------------------------------- /mt76x02_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | * Copyright (C) 2018 Lorenzo Bianconi 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "mt76x02_mcu.h" 12 | 13 | int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd, 14 | struct sk_buff *skb, int seq) 15 | { 16 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 17 | u32 *rxfce; 18 | 19 | if (!skb) { 20 | dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n", 21 | abs(cmd), seq); 22 | dev->mcu_timeout = 1; 23 | return -ETIMEDOUT; 24 | } 25 | 26 | rxfce = (u32 *)skb->cb; 27 | if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) 28 | return -EAGAIN; 29 | 30 | return 0; 31 | } 32 | EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response); 33 | 34 | int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 35 | int len, bool wait_resp) 36 | { 37 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 38 | unsigned long expires = jiffies + HZ; 39 | struct sk_buff *skb; 40 | u32 tx_info; 41 | int ret; 42 | u8 seq; 43 | 44 | if (dev->mcu_timeout) 45 | return -EIO; 46 | 47 | skb = mt76_mcu_msg_alloc(mdev, data, len); 48 | if (!skb) 49 | return -ENOMEM; 50 | 51 | mutex_lock(&mdev->mcu.mutex); 52 | 53 | seq = ++mdev->mcu.msg_seq & 0xf; 54 | if (!seq) 55 | seq = ++mdev->mcu.msg_seq & 0xf; 56 | 57 | tx_info = MT_MCU_MSG_TYPE_CMD | 58 | FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | 59 | FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | 60 | FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | 61 | FIELD_PREP(MT_MCU_MSG_LEN, skb->len); 62 | 63 | ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info); 64 | if (ret) 65 | goto out; 66 | 67 | while (wait_resp) { 68 | skb = mt76_mcu_get_response(&dev->mt76, expires); 69 | ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq); 70 | dev_kfree_skb(skb); 71 | if (ret != -EAGAIN) 72 | break; 73 | } 74 | 75 | out: 76 | mutex_unlock(&mdev->mcu.mutex); 77 | 78 | return ret; 79 | } 80 | EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send); 81 | 82 | int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, 83 | u32 val) 84 | { 85 | struct { 86 | __le32 id; 87 | __le32 value; 88 | } __packed __aligned(4) msg = { 89 | .id = cpu_to_le32(func), 90 | .value = cpu_to_le32(val), 91 | }; 92 | bool wait = false; 93 | 94 | if (func != Q_SELECT) 95 | wait = true; 96 | 97 | return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg, 98 | sizeof(msg), wait); 99 | } 100 | EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select); 101 | 102 | int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on) 103 | { 104 | struct { 105 | __le32 mode; 106 | __le32 level; 107 | } __packed __aligned(4) msg = { 108 | .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), 109 | .level = cpu_to_le32(0), 110 | }; 111 | 112 | return mt76_mcu_send_msg(&dev->mt76, CMD_POWER_SAVING_OP, &msg, 113 | sizeof(msg), false); 114 | } 115 | EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state); 116 | 117 | int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param) 118 | { 119 | struct { 120 | __le32 id; 121 | __le32 value; 122 | } __packed __aligned(4) msg = { 123 | .id = cpu_to_le32(type), 124 | .value = cpu_to_le32(param), 125 | }; 126 | bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev); 127 | int ret; 128 | 129 | if (is_mt76x2e) 130 | mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0); 131 | 132 | ret = mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg, 133 | sizeof(msg), true); 134 | if (ret) 135 | return ret; 136 | 137 | if (is_mt76x2e && 138 | WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0, 139 | BIT(31), BIT(31), 100))) 140 | return -ETIMEDOUT; 141 | 142 | return 0; 143 | } 144 | EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate); 145 | 146 | int mt76x02_mcu_cleanup(struct mt76x02_dev *dev) 147 | { 148 | struct sk_buff *skb; 149 | 150 | mt76_wr(dev, MT_MCU_INT_LEVEL, 1); 151 | usleep_range(20000, 30000); 152 | 153 | while ((skb = skb_dequeue(&dev->mt76.mcu.res_q)) != NULL) 154 | dev_kfree_skb(skb); 155 | 156 | return 0; 157 | } 158 | EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup); 159 | 160 | void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev, 161 | const struct mt76x02_fw_header *h) 162 | { 163 | u16 bld = le16_to_cpu(h->build_ver); 164 | u16 ver = le16_to_cpu(h->fw_ver); 165 | 166 | snprintf(dev->mt76.hw->wiphy->fw_version, 167 | sizeof(dev->mt76.hw->wiphy->fw_version), 168 | "%d.%d.%02d-b%x", 169 | (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld); 170 | } 171 | EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver); 172 | -------------------------------------------------------------------------------- /mt76x02_mcu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x02_MCU_H 7 | #define __MT76x02_MCU_H 8 | 9 | #include "mt76x02.h" 10 | 11 | #define MT_MCU_RESET_CTL 0x070C 12 | #define MT_MCU_INT_LEVEL 0x0718 13 | #define MT_MCU_COM_REG0 0x0730 14 | #define MT_MCU_COM_REG1 0x0734 15 | #define MT_MCU_COM_REG2 0x0738 16 | #define MT_MCU_COM_REG3 0x073C 17 | 18 | #define MT_INBAND_PACKET_MAX_LEN 192 19 | #define MT_MCU_MEMMAP_WLAN 0x410000 20 | 21 | #define MT_MCU_PCIE_REMAP_BASE4 0x074C 22 | 23 | #define MT_MCU_SEMAPHORE_00 0x07B0 24 | #define MT_MCU_SEMAPHORE_01 0x07B4 25 | #define MT_MCU_SEMAPHORE_02 0x07B8 26 | #define MT_MCU_SEMAPHORE_03 0x07BC 27 | 28 | #define MT_MCU_ILM_ADDR 0x80000 29 | 30 | enum mcu_cmd { 31 | CMD_FUN_SET_OP = 1, 32 | CMD_LOAD_CR = 2, 33 | CMD_INIT_GAIN_OP = 3, 34 | CMD_DYNC_VGA_OP = 6, 35 | CMD_TDLS_CH_SW = 7, 36 | CMD_BURST_WRITE = 8, 37 | CMD_READ_MODIFY_WRITE = 9, 38 | CMD_RANDOM_READ = 10, 39 | CMD_BURST_READ = 11, 40 | CMD_RANDOM_WRITE = 12, 41 | CMD_LED_MODE_OP = 16, 42 | CMD_POWER_SAVING_OP = 20, 43 | CMD_WOW_CONFIG = 21, 44 | CMD_WOW_QUERY = 22, 45 | CMD_WOW_FEATURE = 24, 46 | CMD_CARRIER_DETECT_OP = 28, 47 | CMD_RADOR_DETECT_OP = 29, 48 | CMD_SWITCH_CHANNEL_OP = 30, 49 | CMD_CALIBRATION_OP = 31, 50 | CMD_BEACON_OP = 32, 51 | CMD_ANTENNA_OP = 33, 52 | }; 53 | 54 | enum mcu_power_mode { 55 | RADIO_OFF = 0x30, 56 | RADIO_ON = 0x31, 57 | RADIO_OFF_AUTO_WAKEUP = 0x32, 58 | RADIO_OFF_ADVANCE = 0x33, 59 | RADIO_ON_ADVANCE = 0x34, 60 | }; 61 | 62 | enum mcu_function { 63 | Q_SELECT = 1, 64 | BW_SETTING = 2, 65 | USB2_SW_DISCONNECT = 2, 66 | USB3_SW_DISCONNECT = 3, 67 | LOG_FW_DEBUG_MSG = 4, 68 | GET_FW_VERSION = 5, 69 | }; 70 | 71 | struct mt76x02_fw_header { 72 | __le32 ilm_len; 73 | __le32 dlm_len; 74 | __le16 build_ver; 75 | __le16 fw_ver; 76 | u8 pad[4]; 77 | char build_time[16]; 78 | }; 79 | 80 | struct mt76x02_patch_header { 81 | char build_time[16]; 82 | char platform[4]; 83 | char hw_version[4]; 84 | char patch_version[4]; 85 | u8 pad[2]; 86 | }; 87 | 88 | int mt76x02_mcu_cleanup(struct mt76x02_dev *dev); 89 | int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param); 90 | int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 91 | int len, bool wait_resp); 92 | int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd, 93 | struct sk_buff *skb, int seq); 94 | int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, 95 | u32 val); 96 | int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on); 97 | void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev, 98 | const struct mt76x02_fw_header *h); 99 | 100 | #endif /* __MT76x02_MCU_H */ 101 | -------------------------------------------------------------------------------- /mt76x02_phy.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x02_PHY_H 7 | #define __MT76x02_PHY_H 8 | 9 | #include "mt76x02_regs.h" 10 | 11 | static inline int 12 | mt76x02_get_rssi_gain_thresh(struct mt76x02_dev *dev) 13 | { 14 | switch (dev->mphy.chandef.width) { 15 | case NL80211_CHAN_WIDTH_80: 16 | return -62; 17 | case NL80211_CHAN_WIDTH_40: 18 | return -65; 19 | default: 20 | return -68; 21 | } 22 | } 23 | 24 | static inline int 25 | mt76x02_get_low_rssi_gain_thresh(struct mt76x02_dev *dev) 26 | { 27 | switch (dev->mphy.chandef.width) { 28 | case NL80211_CHAN_WIDTH_80: 29 | return -76; 30 | case NL80211_CHAN_WIDTH_40: 31 | return -79; 32 | default: 33 | return -82; 34 | } 35 | } 36 | 37 | void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset); 38 | void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_2); 39 | void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); 40 | int mt76x02_get_max_rate_power(struct mt76_rate_power *r); 41 | void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev); 42 | void mt76x02_phy_set_txdac(struct mt76x02_dev *dev); 43 | void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); 44 | void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, 45 | bool primary_upper); 46 | bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev); 47 | void mt76x02_init_agc_gain(struct mt76x02_dev *dev); 48 | 49 | #endif /* __MT76x02_PHY_H */ 50 | -------------------------------------------------------------------------------- /mt76x02_trace.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | 8 | #ifndef __CHECKER__ 9 | #define CREATE_TRACE_POINTS 10 | #include "mt76x02_trace.h" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /mt76x02_trace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #if !defined(__MT76x02_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 7 | #define __MT76x02_TRACE_H 8 | 9 | #include 10 | #include "mt76x02.h" 11 | 12 | #undef TRACE_SYSTEM 13 | #define TRACE_SYSTEM mt76x02 14 | 15 | #define MAXNAME 32 16 | #define DEV_ENTRY __array(char, wiphy_name, 32) 17 | #define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ 18 | wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) 19 | #define DEV_PR_FMT "%s" 20 | #define DEV_PR_ARG __entry->wiphy_name 21 | 22 | #define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) 23 | #define TXID_PR_FMT " [%d:%d]" 24 | #define TXID_PR_ARG __entry->wcid, __entry->pktid 25 | 26 | DECLARE_EVENT_CLASS(dev_evt, 27 | TP_PROTO(struct mt76x02_dev *dev), 28 | TP_ARGS(dev), 29 | TP_STRUCT__entry( 30 | DEV_ENTRY 31 | ), 32 | TP_fast_assign( 33 | DEV_ASSIGN; 34 | ), 35 | TP_printk(DEV_PR_FMT, DEV_PR_ARG) 36 | ); 37 | 38 | DEFINE_EVENT(dev_evt, mac_txstat_poll, 39 | TP_PROTO(struct mt76x02_dev *dev), 40 | TP_ARGS(dev) 41 | ); 42 | 43 | TRACE_EVENT(mac_txstat_fetch, 44 | TP_PROTO(struct mt76x02_dev *dev, 45 | struct mt76x02_tx_status *stat), 46 | 47 | TP_ARGS(dev, stat), 48 | 49 | TP_STRUCT__entry( 50 | DEV_ENTRY 51 | TXID_ENTRY 52 | __field(bool, success) 53 | __field(bool, aggr) 54 | __field(bool, ack_req) 55 | __field(u16, rate) 56 | __field(u8, retry) 57 | ), 58 | 59 | TP_fast_assign( 60 | DEV_ASSIGN; 61 | __entry->success = stat->success; 62 | __entry->aggr = stat->aggr; 63 | __entry->ack_req = stat->ack_req; 64 | __entry->wcid = stat->wcid; 65 | __entry->pktid = stat->pktid; 66 | __entry->rate = stat->rate; 67 | __entry->retry = stat->retry; 68 | ), 69 | 70 | TP_printk( 71 | DEV_PR_FMT TXID_PR_FMT 72 | " success:%d aggr:%d ack_req:%d" 73 | " rate:%04x retry:%d", 74 | DEV_PR_ARG, TXID_PR_ARG, 75 | __entry->success, __entry->aggr, __entry->ack_req, 76 | __entry->rate, __entry->retry 77 | ) 78 | ); 79 | 80 | #endif 81 | 82 | #undef TRACE_INCLUDE_PATH 83 | #define TRACE_INCLUDE_PATH . 84 | #undef TRACE_INCLUDE_FILE 85 | #define TRACE_INCLUDE_FILE mt76x02_trace 86 | 87 | #include 88 | -------------------------------------------------------------------------------- /mt76x02_usb.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x02_USB_H 7 | #define __MT76x02_USB_H 8 | 9 | #include "mt76x02.h" 10 | 11 | int mt76x02u_mac_start(struct mt76x02_dev *dev); 12 | void mt76x02u_init_mcu(struct mt76_dev *dev); 13 | void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev); 14 | int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, 15 | int data_len, u32 max_payload, u32 offset); 16 | 17 | int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); 18 | int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, 19 | enum mt76_txq_id qid, struct mt76_wcid *wcid, 20 | struct ieee80211_sta *sta, 21 | struct mt76_tx_info *tx_info); 22 | void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); 23 | void mt76x02u_init_beacon_config(struct mt76x02_dev *dev); 24 | void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev); 25 | #endif /* __MT76x02_USB_H */ 26 | -------------------------------------------------------------------------------- /mt76x2/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o 3 | obj-$(CONFIG_MT76x2E) += mt76x2e.o 4 | obj-$(CONFIG_MT76x2U) += mt76x2u.o 5 | 6 | mt76x2-common-y := \ 7 | eeprom.o mac.o init.o phy.o mcu.o 8 | 9 | mt76x2e-y := \ 10 | pci.o pci_main.o pci_init.o pci_mcu.o \ 11 | pci_phy.o 12 | 13 | mt76x2u-y := \ 14 | usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \ 15 | usb_phy.o 16 | -------------------------------------------------------------------------------- /mt76x2/debugfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Felix Fietkau 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include "mt76x02.h" 19 | 20 | static int 21 | mt76x02_ampdu_stat_read(struct seq_file *file, void *data) 22 | { 23 | struct mt76x02_dev *dev = file->private; 24 | int i, j; 25 | 26 | for (i = 0; i < 4; i++) { 27 | seq_puts(file, "Length: "); 28 | for (j = 0; j < 8; j++) 29 | seq_printf(file, "%8d | ", i * 8 + j + 1); 30 | seq_puts(file, "\n"); 31 | seq_puts(file, "Count: "); 32 | for (j = 0; j < 8; j++) 33 | seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); 34 | seq_puts(file, "\n"); 35 | seq_puts(file, "--------"); 36 | for (j = 0; j < 8; j++) 37 | seq_puts(file, "-----------"); 38 | seq_puts(file, "\n"); 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | static int 45 | mt76x02_ampdu_stat_open(struct inode *inode, struct file *f) 46 | { 47 | return single_open(f, mt76x02_ampdu_stat_read, inode->i_private); 48 | } 49 | 50 | static int read_txpower(struct seq_file *file, void *data) 51 | { 52 | struct mt76x02_dev *dev = dev_get_drvdata(file->private); 53 | 54 | seq_printf(file, "Target power: %d\n", dev->target_power); 55 | 56 | mt76_seq_puts_array(file, "Delta", dev->target_power_delta, 57 | ARRAY_SIZE(dev->target_power_delta)); 58 | return 0; 59 | } 60 | 61 | static const struct file_operations fops_ampdu_stat = { 62 | .open = mt76x02_ampdu_stat_open, 63 | .read = seq_read, 64 | .llseek = seq_lseek, 65 | .release = single_release, 66 | }; 67 | 68 | static int 69 | mt76x02_dfs_stat_read(struct seq_file *file, void *data) 70 | { 71 | struct mt76x02_dev *dev = file->private; 72 | struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 73 | int i; 74 | 75 | seq_printf(file, "allocated sequences:\t%d\n", 76 | dfs_pd->seq_stats.seq_pool_len); 77 | seq_printf(file, "used sequences:\t\t%d\n", 78 | dfs_pd->seq_stats.seq_len); 79 | seq_puts(file, "\n"); 80 | 81 | for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { 82 | seq_printf(file, "engine: %d\n", i); 83 | seq_printf(file, " hw pattern detected:\t%d\n", 84 | dfs_pd->stats[i].hw_pattern); 85 | seq_printf(file, " hw pulse discarded:\t%d\n", 86 | dfs_pd->stats[i].hw_pulse_discarded); 87 | seq_printf(file, " sw pattern detected:\t%d\n", 88 | dfs_pd->stats[i].sw_pattern); 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | static int 95 | mt76x02_dfs_stat_open(struct inode *inode, struct file *f) 96 | { 97 | return single_open(f, mt76x02_dfs_stat_read, inode->i_private); 98 | } 99 | 100 | static const struct file_operations fops_dfs_stat = { 101 | .open = mt76x02_dfs_stat_open, 102 | .read = seq_read, 103 | .llseek = seq_lseek, 104 | .release = single_release, 105 | }; 106 | 107 | static int read_agc(struct seq_file *file, void *data) 108 | { 109 | struct mt76x02_dev *dev = dev_get_drvdata(file->private); 110 | 111 | seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); 112 | seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); 113 | seq_printf(file, "false_cca: %d\n", dev->cal.false_cca); 114 | seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust); 115 | 116 | return 0; 117 | } 118 | 119 | void mt76x02_init_debugfs(struct mt76x02_dev *dev) 120 | { 121 | struct dentry *dir; 122 | 123 | dir = mt76_register_debugfs(&dev->mt76); 124 | if (!dir) 125 | return; 126 | 127 | debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); 128 | debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); 129 | 130 | debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); 131 | debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat); 132 | debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, 133 | read_txpower); 134 | 135 | debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); 136 | } 137 | EXPORT_SYMBOL_GPL(mt76x02_init_debugfs); 138 | -------------------------------------------------------------------------------- /mt76x2/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #ifndef __MT76x2_EEPROM_H 7 | #define __MT76x2_EEPROM_H 8 | 9 | #include "../mt76x02_eeprom.h" 10 | 11 | enum mt76x2_cal_channel_group { 12 | MT_CH_5G_JAPAN, 13 | MT_CH_5G_UNII_1, 14 | MT_CH_5G_UNII_2, 15 | MT_CH_5G_UNII_2E_1, 16 | MT_CH_5G_UNII_2E_2, 17 | MT_CH_5G_UNII_3, 18 | __MT_CH_MAX 19 | }; 20 | 21 | struct mt76x2_tx_power_info { 22 | u8 target_power; 23 | 24 | s8 delta_bw40; 25 | s8 delta_bw80; 26 | 27 | struct { 28 | s8 tssi_slope; 29 | s8 tssi_offset; 30 | s8 target_power; 31 | s8 delta; 32 | } chain[MT_MAX_CHAINS]; 33 | }; 34 | 35 | struct mt76x2_temp_comp { 36 | u8 temp_25_ref; 37 | int lower_bound; /* J */ 38 | int upper_bound; /* J */ 39 | unsigned int high_slope; /* J / dB */ 40 | unsigned int low_slope; /* J / dB */ 41 | }; 42 | 43 | void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t, 44 | struct ieee80211_channel *chan); 45 | void mt76x2_get_power_info(struct mt76x02_dev *dev, 46 | struct mt76x2_tx_power_info *t, 47 | struct ieee80211_channel *chan); 48 | int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t); 49 | void mt76x2_read_rx_gain(struct mt76x02_dev *dev); 50 | 51 | static inline bool 52 | mt76x2_has_ext_lna(struct mt76x02_dev *dev) 53 | { 54 | u32 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 55 | 56 | if (dev->mphy.chandef.chan->band == NL80211_BAND_2GHZ) 57 | return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; 58 | else 59 | return val & MT_EE_NIC_CONF_1_LNA_EXT_5G; 60 | } 61 | 62 | static inline bool 63 | mt76x2_temp_tx_alc_enabled(struct mt76x02_dev *dev) 64 | { 65 | u16 val; 66 | 67 | val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); 68 | if (!(val & BIT(15))) 69 | return false; 70 | 71 | return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & 72 | MT_EE_NIC_CONF_1_TEMP_TX_ALC; 73 | } 74 | 75 | static inline bool 76 | mt76x2_tssi_enabled(struct mt76x02_dev *dev) 77 | { 78 | return !mt76x2_temp_tx_alc_enabled(dev) && 79 | (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & 80 | MT_EE_NIC_CONF_1_TX_ALC_EN); 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /mt76x2/mac.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | * Copyright (C) 2018 Lorenzo Bianconi 5 | */ 6 | 7 | #include "mt76x2.h" 8 | 9 | void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force) 10 | { 11 | bool stopped = false; 12 | u32 rts_cfg; 13 | int i; 14 | 15 | mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); 16 | mt76_clear(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN); 17 | 18 | mt76_wr(dev, MT_MAC_SYS_CTRL, 0); 19 | 20 | rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); 21 | mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); 22 | 23 | /* Wait for MAC to become idle */ 24 | for (i = 0; i < 300; i++) { 25 | if ((mt76_rr(dev, MT_MAC_STATUS) & 26 | (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || 27 | mt76_rr(dev, MT_BBP(IBI, 12))) { 28 | udelay(1); 29 | continue; 30 | } 31 | 32 | stopped = true; 33 | break; 34 | } 35 | 36 | if (force && !stopped) { 37 | mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); 38 | mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); 39 | 40 | mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); 41 | mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); 42 | } 43 | 44 | mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); 45 | } 46 | EXPORT_SYMBOL_GPL(mt76x2_mac_stop); 47 | -------------------------------------------------------------------------------- /mt76x2/mac.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #ifndef __MT76x2_MAC_H 7 | #define __MT76x2_MAC_H 8 | 9 | #include "mt76x2.h" 10 | 11 | struct mt76x02_dev; 12 | struct mt76x2_sta; 13 | struct mt76x02_vif; 14 | 15 | void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); 16 | 17 | static inline void mt76x2_mac_resume(struct mt76x02_dev *dev) 18 | { 19 | mt76_wr(dev, MT_MAC_SYS_CTRL, 20 | MT_MAC_SYS_CTRL_ENABLE_TX | 21 | MT_MAC_SYS_CTRL_ENABLE_RX); 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /mt76x2/mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | * Copyright (C) 2018 Lorenzo Bianconi 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "mt76x2.h" 12 | #include "mcu.h" 13 | #include "eeprom.h" 14 | 15 | int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, 16 | u8 bw_index, bool scan) 17 | { 18 | struct { 19 | u8 idx; 20 | u8 scan; 21 | u8 bw; 22 | u8 _pad0; 23 | 24 | __le16 chainmask; 25 | u8 ext_chan; 26 | u8 _pad1; 27 | 28 | } __packed __aligned(4) msg = { 29 | .idx = channel, 30 | .scan = scan, 31 | .bw = bw, 32 | .chainmask = cpu_to_le16(dev->mphy.chainmask), 33 | }; 34 | 35 | /* first set the channel without the extension channel info */ 36 | mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg, 37 | sizeof(msg), true); 38 | 39 | usleep_range(5000, 10000); 40 | 41 | msg.ext_chan = 0xe0 + bw_index; 42 | return mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg, 43 | sizeof(msg), true); 44 | } 45 | EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); 46 | 47 | int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, 48 | u8 channel) 49 | { 50 | struct { 51 | u8 cr_mode; 52 | u8 temp; 53 | u8 ch; 54 | u8 _pad0; 55 | 56 | __le32 cfg; 57 | } __packed __aligned(4) msg = { 58 | .cr_mode = type, 59 | .temp = temp_level, 60 | .ch = channel, 61 | }; 62 | u32 val; 63 | 64 | val = BIT(31); 65 | val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; 66 | val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; 67 | msg.cfg = cpu_to_le32(val); 68 | 69 | /* first set the channel without the extension channel info */ 70 | return mt76_mcu_send_msg(&dev->mt76, CMD_LOAD_CR, &msg, sizeof(msg), 71 | true); 72 | } 73 | EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); 74 | 75 | int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, 76 | bool force) 77 | { 78 | struct { 79 | __le32 channel; 80 | __le32 gain_val; 81 | } __packed __aligned(4) msg = { 82 | .channel = cpu_to_le32(channel), 83 | .gain_val = cpu_to_le32(gain), 84 | }; 85 | 86 | if (force) 87 | msg.channel |= cpu_to_le32(BIT(31)); 88 | 89 | return mt76_mcu_send_msg(&dev->mt76, CMD_INIT_GAIN_OP, &msg, 90 | sizeof(msg), true); 91 | } 92 | EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); 93 | 94 | int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, 95 | struct mt76x2_tssi_comp *tssi_data) 96 | { 97 | struct { 98 | __le32 id; 99 | struct mt76x2_tssi_comp data; 100 | } __packed __aligned(4) msg = { 101 | .id = cpu_to_le32(MCU_CAL_TSSI_COMP), 102 | .data = *tssi_data, 103 | }; 104 | 105 | return mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg, 106 | sizeof(msg), true); 107 | } 108 | EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp); 109 | -------------------------------------------------------------------------------- /mt76x2/mcu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #ifndef __MT76x2_MCU_H 7 | #define __MT76x2_MCU_H 8 | 9 | #include "../mt76x02_mcu.h" 10 | 11 | /* Register definitions */ 12 | #define MT_MCU_CPU_CTL 0x0704 13 | #define MT_MCU_CLOCK_CTL 0x0708 14 | #define MT_MCU_PCIE_REMAP_BASE1 0x0740 15 | #define MT_MCU_PCIE_REMAP_BASE2 0x0744 16 | #define MT_MCU_PCIE_REMAP_BASE3 0x0748 17 | 18 | #define MT_MCU_ROM_PATCH_OFFSET 0x80000 19 | #define MT_MCU_ROM_PATCH_ADDR 0x90000 20 | 21 | #define MT_MCU_ILM_OFFSET 0x80000 22 | 23 | #define MT_MCU_DLM_OFFSET 0x100000 24 | #define MT_MCU_DLM_ADDR 0x90000 25 | #define MT_MCU_DLM_ADDR_E3 0x90800 26 | 27 | enum mcu_calibration { 28 | MCU_CAL_R = 1, 29 | MCU_CAL_TEMP_SENSOR, 30 | MCU_CAL_RXDCOC, 31 | MCU_CAL_RC, 32 | MCU_CAL_SX_LOGEN, 33 | MCU_CAL_LC, 34 | MCU_CAL_TX_LOFT, 35 | MCU_CAL_TXIQ, 36 | MCU_CAL_TSSI, 37 | MCU_CAL_TSSI_COMP, 38 | MCU_CAL_DPD, 39 | MCU_CAL_RXIQC_FI, 40 | MCU_CAL_RXIQC_FD, 41 | MCU_CAL_PWRON, 42 | MCU_CAL_TX_SHAPING, 43 | }; 44 | 45 | enum mt76x2_mcu_cr_mode { 46 | MT_RF_CR, 47 | MT_BBP_CR, 48 | MT_RF_BBP_CR, 49 | MT_HL_TEMP_CR_UPDATE, 50 | }; 51 | 52 | struct mt76x2_tssi_comp { 53 | u8 pa_mode; 54 | u8 cal_mode; 55 | u16 pad; 56 | 57 | u8 slope0; 58 | u8 slope1; 59 | u8 offset0; 60 | u8 offset1; 61 | } __packed __aligned(4); 62 | 63 | int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, 64 | struct mt76x2_tssi_comp *tssi_data); 65 | int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, 66 | bool force); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /mt76x2/mt76x2.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #ifndef __MT76x2_H 7 | #define __MT76x2_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define MT7662_FIRMWARE "mt7662.bin" 20 | #define MT7662_ROM_PATCH "mt7662_rom_patch.bin" 21 | #define MT7662_EEPROM_SIZE 512 22 | 23 | #include "../mt76x02.h" 24 | #include "mac.h" 25 | 26 | static inline bool is_mt7612(struct mt76x02_dev *dev) 27 | { 28 | return mt76_chip(&dev->mt76) == 0x7612; 29 | } 30 | 31 | static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) 32 | { 33 | struct ieee80211_channel *chan = dev->mphy.chandef.chan; 34 | 35 | return ((chan->flags & IEEE80211_CHAN_RADAR) && 36 | chan->dfs_state != NL80211_DFS_AVAILABLE); 37 | } 38 | 39 | extern const struct ieee80211_ops mt76x2_ops; 40 | 41 | int mt76x2_register_device(struct mt76x02_dev *dev); 42 | int mt76x2_resume_device(struct mt76x02_dev *dev); 43 | 44 | int mt76x2_set_sar_specs(struct ieee80211_hw *hw, 45 | const struct cfg80211_sar_specs *sar); 46 | void mt76x2_phy_power_on(struct mt76x02_dev *dev); 47 | void mt76x2_stop_hardware(struct mt76x02_dev *dev); 48 | int mt76x2_eeprom_init(struct mt76x02_dev *dev); 49 | int mt76x2_apply_calibration_data(struct mt76x02_dev *dev, int channel); 50 | 51 | void mt76x2_phy_set_antenna(struct mt76x02_dev *dev); 52 | int mt76x2_phy_start(struct mt76x02_dev *dev); 53 | int mt76x2_phy_set_channel(struct mt76x02_dev *dev, 54 | struct cfg80211_chan_def *chandef); 55 | void mt76x2_phy_calibrate(struct work_struct *work); 56 | void mt76x2_phy_set_txpower(struct mt76x02_dev *dev); 57 | 58 | int mt76x2_mcu_init(struct mt76x02_dev *dev); 59 | int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, 60 | u8 bw_index, bool scan); 61 | int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, 62 | u8 channel); 63 | 64 | void mt76x2_cleanup(struct mt76x02_dev *dev); 65 | 66 | int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard); 67 | void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable); 68 | void mt76x2_init_txpower(struct mt76x02_dev *dev, 69 | struct ieee80211_supported_band *sband); 70 | void mt76_write_mac_initvals(struct mt76x02_dev *dev); 71 | 72 | void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev); 73 | void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, 74 | enum nl80211_band band); 75 | void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, 76 | enum nl80211_band band, u8 bw); 77 | void mt76x2_apply_gain_adj(struct mt76x02_dev *dev); 78 | void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /mt76x2/mt76x2u.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #ifndef __MT76x2U_H 7 | #define __MT76x2U_H 8 | 9 | #include 10 | 11 | #include "mt76x2.h" 12 | #include "mcu.h" 13 | 14 | #define MT7612U_EEPROM_SIZE 512 15 | 16 | #define MT_USB_AGGR_SIZE_LIMIT 21 /* 1024B unit */ 17 | #define MT_USB_AGGR_TIMEOUT 0x80 /* 33ns unit */ 18 | 19 | extern const struct ieee80211_ops mt76x2u_ops; 20 | 21 | int mt76x2u_register_device(struct mt76x02_dev *dev); 22 | int mt76x2u_init_hardware(struct mt76x02_dev *dev); 23 | void mt76x2u_cleanup(struct mt76x02_dev *dev); 24 | void mt76x2u_stop_hw(struct mt76x02_dev *dev); 25 | 26 | int mt76x2u_mac_reset(struct mt76x02_dev *dev); 27 | int mt76x2u_mac_stop(struct mt76x02_dev *dev); 28 | 29 | int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, 30 | struct cfg80211_chan_def *chandef); 31 | void mt76x2u_phy_calibrate(struct work_struct *work); 32 | 33 | void mt76x2u_mcu_complete_urb(struct urb *urb); 34 | int mt76x2u_mcu_init(struct mt76x02_dev *dev); 35 | int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev); 36 | 37 | int mt76x2u_alloc_queues(struct mt76x02_dev *dev); 38 | void mt76x2u_queues_deinit(struct mt76x02_dev *dev); 39 | void mt76x2u_stop_queues(struct mt76x02_dev *dev); 40 | int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, 41 | u32 flags); 42 | 43 | #endif /* __MT76x2U_H */ 44 | -------------------------------------------------------------------------------- /mt76x2/pci.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "mt76x2.h" 11 | 12 | static const struct pci_device_id mt76x2e_device_table[] = { 13 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7662) }, 14 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7612) }, 15 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7602) }, 16 | { }, 17 | }; 18 | 19 | static int 20 | mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) 21 | { 22 | static const struct mt76_driver_ops drv_ops = { 23 | .txwi_size = sizeof(struct mt76x02_txwi), 24 | .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | 25 | MT_DRV_SW_RX_AIRTIME, 26 | .survey_flags = SURVEY_INFO_TIME_TX, 27 | .update_survey = mt76x02_update_channel, 28 | .tx_prepare_skb = mt76x02_tx_prepare_skb, 29 | .tx_complete_skb = mt76x02_tx_complete_skb, 30 | .rx_skb = mt76x02_queue_rx_skb, 31 | .rx_poll_complete = mt76x02_rx_poll_complete, 32 | .sta_ps = mt76x02_sta_ps, 33 | .sta_add = mt76x02_sta_add, 34 | .sta_remove = mt76x02_sta_remove, 35 | }; 36 | struct mt76x02_dev *dev; 37 | struct mt76_dev *mdev; 38 | int ret; 39 | 40 | ret = pcim_enable_device(pdev); 41 | if (ret) 42 | return ret; 43 | 44 | ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 45 | if (ret) 46 | return ret; 47 | 48 | pci_set_master(pdev); 49 | 50 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 51 | if (ret) 52 | return ret; 53 | 54 | mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x2_ops, 55 | &drv_ops); 56 | if (!mdev) 57 | return -ENOMEM; 58 | 59 | dev = container_of(mdev, struct mt76x02_dev, mt76); 60 | mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); 61 | mt76x2_reset_wlan(dev, false); 62 | 63 | mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 64 | dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 65 | 66 | mt76_wr(dev, MT_INT_MASK_CSR, 0); 67 | 68 | ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, 69 | IRQF_SHARED, KBUILD_MODNAME, dev); 70 | if (ret) 71 | goto error; 72 | 73 | ret = mt76x2_register_device(dev); 74 | if (ret) 75 | goto error; 76 | 77 | /* Fix up ASPM configuration */ 78 | 79 | /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ 80 | mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); 81 | 82 | /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ 83 | mt76_rmw_field(dev, 0x15a0c, 0xf << 28, 0xf); 84 | 85 | /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ 86 | mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); 87 | 88 | mt76_pci_disable_aspm(pdev); 89 | 90 | return 0; 91 | 92 | error: 93 | mt76_free_device(&dev->mt76); 94 | 95 | return ret; 96 | } 97 | 98 | static void 99 | mt76x2e_remove(struct pci_dev *pdev) 100 | { 101 | struct mt76_dev *mdev = pci_get_drvdata(pdev); 102 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 103 | 104 | mt76_unregister_device(mdev); 105 | mt76x2_cleanup(dev); 106 | mt76_free_device(mdev); 107 | } 108 | 109 | static int __maybe_unused 110 | mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state) 111 | { 112 | struct mt76_dev *mdev = pci_get_drvdata(pdev); 113 | int i, err; 114 | 115 | napi_disable(&mdev->tx_napi); 116 | tasklet_kill(&mdev->pre_tbtt_tasklet); 117 | mt76_worker_disable(&mdev->tx_worker); 118 | 119 | mt76_for_each_q_rx(mdev, i) 120 | napi_disable(&mdev->napi[i]); 121 | 122 | pci_enable_wake(pdev, pci_choose_state(pdev, state), true); 123 | pci_save_state(pdev); 124 | err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); 125 | if (err) 126 | goto restore; 127 | 128 | return 0; 129 | 130 | restore: 131 | mt76_for_each_q_rx(mdev, i) 132 | napi_enable(&mdev->napi[i]); 133 | napi_enable(&mdev->tx_napi); 134 | 135 | return err; 136 | } 137 | 138 | static int __maybe_unused 139 | mt76x2e_resume(struct pci_dev *pdev) 140 | { 141 | struct mt76_dev *mdev = pci_get_drvdata(pdev); 142 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 143 | int i, err; 144 | 145 | err = pci_set_power_state(pdev, PCI_D0); 146 | if (err) 147 | return err; 148 | 149 | pci_restore_state(pdev); 150 | 151 | mt76_worker_enable(&mdev->tx_worker); 152 | 153 | local_bh_disable(); 154 | mt76_for_each_q_rx(mdev, i) { 155 | napi_enable(&mdev->napi[i]); 156 | napi_schedule(&mdev->napi[i]); 157 | } 158 | napi_enable(&mdev->tx_napi); 159 | napi_schedule(&mdev->tx_napi); 160 | local_bh_enable(); 161 | 162 | return mt76x2_resume_device(dev); 163 | } 164 | 165 | MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); 166 | MODULE_FIRMWARE(MT7662_FIRMWARE); 167 | MODULE_FIRMWARE(MT7662_ROM_PATCH); 168 | MODULE_LICENSE("Dual BSD/GPL"); 169 | 170 | static struct pci_driver mt76pci_driver = { 171 | .name = KBUILD_MODNAME, 172 | .id_table = mt76x2e_device_table, 173 | .probe = mt76x2e_probe, 174 | .remove = mt76x2e_remove, 175 | #ifdef CONFIG_PM 176 | .suspend = mt76x2e_suspend, 177 | .resume = mt76x2e_resume, 178 | #endif /* CONFIG_PM */ 179 | }; 180 | 181 | module_pci_driver(mt76pci_driver); 182 | -------------------------------------------------------------------------------- /mt76x2/pci_main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include "mt76x2.h" 7 | #include "../mt76x02_mac.h" 8 | 9 | static int 10 | mt76x2_start(struct ieee80211_hw *hw) 11 | { 12 | struct mt76x02_dev *dev = hw->priv; 13 | 14 | mt76x02_mac_start(dev); 15 | mt76x2_phy_start(dev); 16 | 17 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, 18 | MT_MAC_WORK_INTERVAL); 19 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, 20 | MT_WATCHDOG_TIME); 21 | 22 | set_bit(MT76_STATE_RUNNING, &dev->mphy.state); 23 | return 0; 24 | } 25 | 26 | static void 27 | mt76x2_stop(struct ieee80211_hw *hw) 28 | { 29 | struct mt76x02_dev *dev = hw->priv; 30 | 31 | clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); 32 | mt76x2_stop_hardware(dev); 33 | } 34 | 35 | static void 36 | mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) 37 | { 38 | cancel_delayed_work_sync(&dev->cal_work); 39 | tasklet_disable(&dev->mt76.pre_tbtt_tasklet); 40 | tasklet_disable(&dev->dfs_pd.dfs_tasklet); 41 | 42 | mutex_lock(&dev->mt76.mutex); 43 | set_bit(MT76_RESET, &dev->mphy.state); 44 | 45 | mt76_set_channel(&dev->mphy); 46 | 47 | mt76x2_mac_stop(dev, true); 48 | mt76x2_phy_set_channel(dev, chandef); 49 | 50 | mt76x02_mac_cc_reset(dev); 51 | mt76x02_dfs_init_params(dev); 52 | 53 | mt76x2_mac_resume(dev); 54 | 55 | clear_bit(MT76_RESET, &dev->mphy.state); 56 | mutex_unlock(&dev->mt76.mutex); 57 | 58 | tasklet_enable(&dev->dfs_pd.dfs_tasklet); 59 | tasklet_enable(&dev->mt76.pre_tbtt_tasklet); 60 | 61 | mt76_txq_schedule_all(&dev->mphy); 62 | } 63 | 64 | static int 65 | mt76x2_config(struct ieee80211_hw *hw, u32 changed) 66 | { 67 | struct mt76x02_dev *dev = hw->priv; 68 | 69 | mutex_lock(&dev->mt76.mutex); 70 | 71 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 72 | if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) 73 | dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; 74 | else 75 | dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; 76 | 77 | mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 78 | } 79 | 80 | if (changed & IEEE80211_CONF_CHANGE_POWER) { 81 | struct mt76_phy *mphy = &dev->mphy; 82 | 83 | dev->txpower_conf = hw->conf.power_level * 2; 84 | dev->txpower_conf = mt76_get_sar_power(mphy, 85 | mphy->chandef.chan, 86 | dev->txpower_conf); 87 | /* convert to per-chain power for 2x2 devices */ 88 | dev->txpower_conf -= 6; 89 | 90 | if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { 91 | mt76x2_phy_set_txpower(dev); 92 | mt76x02_tx_set_txpwr_auto(dev, dev->txpower_conf); 93 | } 94 | } 95 | 96 | mutex_unlock(&dev->mt76.mutex); 97 | 98 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 99 | ieee80211_stop_queues(hw); 100 | mt76x2_set_channel(dev, &hw->conf.chandef); 101 | ieee80211_wake_queues(hw); 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | static void 108 | mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 109 | u32 queues, bool drop) 110 | { 111 | } 112 | 113 | static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, 114 | u32 rx_ant) 115 | { 116 | struct mt76x02_dev *dev = hw->priv; 117 | 118 | if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) 119 | return -EINVAL; 120 | 121 | mutex_lock(&dev->mt76.mutex); 122 | 123 | dev->mphy.chainmask = (tx_ant == 3) ? 0x202 : 0x101; 124 | dev->mphy.antenna_mask = tx_ant; 125 | 126 | mt76_set_stream_caps(&dev->mphy, true); 127 | mt76x2_phy_set_antenna(dev); 128 | 129 | mutex_unlock(&dev->mt76.mutex); 130 | 131 | return 0; 132 | } 133 | 134 | const struct ieee80211_ops mt76x2_ops = { 135 | .tx = mt76x02_tx, 136 | .start = mt76x2_start, 137 | .stop = mt76x2_stop, 138 | .add_interface = mt76x02_add_interface, 139 | .remove_interface = mt76x02_remove_interface, 140 | .config = mt76x2_config, 141 | .configure_filter = mt76x02_configure_filter, 142 | .bss_info_changed = mt76x02_bss_info_changed, 143 | .sta_state = mt76_sta_state, 144 | .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 145 | .set_key = mt76x02_set_key, 146 | .conf_tx = mt76x02_conf_tx, 147 | .sw_scan_start = mt76_sw_scan, 148 | .sw_scan_complete = mt76x02_sw_scan_complete, 149 | .flush = mt76x2_flush, 150 | .ampdu_action = mt76x02_ampdu_action, 151 | .get_txpower = mt76_get_txpower, 152 | .wake_tx_queue = mt76_wake_tx_queue, 153 | .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, 154 | .release_buffered_frames = mt76_release_buffered_frames, 155 | .set_coverage_class = mt76x02_set_coverage_class, 156 | .get_survey = mt76_get_survey, 157 | .set_tim = mt76_set_tim, 158 | .set_antenna = mt76x2_set_antenna, 159 | .get_antenna = mt76_get_antenna, 160 | .set_rts_threshold = mt76x02_set_rts_threshold, 161 | .reconfig_complete = mt76x02_reconfig_complete, 162 | .set_sar_specs = mt76x2_set_sar_specs, 163 | }; 164 | 165 | -------------------------------------------------------------------------------- /mt76x2/pci_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "mt76x2.h" 11 | #include "mcu.h" 12 | #include "eeprom.h" 13 | 14 | static int 15 | mt76pci_load_rom_patch(struct mt76x02_dev *dev) 16 | { 17 | const struct firmware *fw = NULL; 18 | struct mt76x02_patch_header *hdr; 19 | bool rom_protect = !is_mt7612(dev); 20 | int len, ret = 0; 21 | __le32 *cur; 22 | u32 patch_mask, patch_reg; 23 | 24 | if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { 25 | dev_err(dev->mt76.dev, 26 | "Could not get hardware semaphore for ROM PATCH\n"); 27 | return -ETIMEDOUT; 28 | } 29 | 30 | if (mt76xx_rev(dev) >= MT76XX_REV_E3) { 31 | patch_mask = BIT(0); 32 | patch_reg = MT_MCU_CLOCK_CTL; 33 | } else { 34 | patch_mask = BIT(1); 35 | patch_reg = MT_MCU_COM_REG0; 36 | } 37 | 38 | if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { 39 | dev_info(dev->mt76.dev, "ROM patch already applied\n"); 40 | goto out; 41 | } 42 | 43 | ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev); 44 | if (ret) 45 | goto out; 46 | 47 | if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { 48 | ret = -EIO; 49 | dev_err(dev->mt76.dev, "Failed to load firmware\n"); 50 | goto out; 51 | } 52 | 53 | hdr = (struct mt76x02_patch_header *)fw->data; 54 | dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); 55 | 56 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); 57 | 58 | cur = (__le32 *)(fw->data + sizeof(*hdr)); 59 | len = fw->size - sizeof(*hdr); 60 | mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len); 61 | 62 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); 63 | 64 | /* Trigger ROM */ 65 | mt76_wr(dev, MT_MCU_INT_LEVEL, 4); 66 | 67 | if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) { 68 | dev_err(dev->mt76.dev, "Failed to load ROM patch\n"); 69 | ret = -ETIMEDOUT; 70 | } 71 | 72 | out: 73 | /* release semaphore */ 74 | if (rom_protect) 75 | mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); 76 | release_firmware(fw); 77 | return ret; 78 | } 79 | 80 | static int 81 | mt76pci_load_firmware(struct mt76x02_dev *dev) 82 | { 83 | const struct firmware *fw; 84 | const struct mt76x02_fw_header *hdr; 85 | int len, ret; 86 | __le32 *cur; 87 | u32 offset, val; 88 | 89 | ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev); 90 | if (ret) 91 | return ret; 92 | 93 | if (!fw || !fw->data || fw->size < sizeof(*hdr)) 94 | goto error; 95 | 96 | hdr = (const struct mt76x02_fw_header *)fw->data; 97 | 98 | len = sizeof(*hdr); 99 | len += le32_to_cpu(hdr->ilm_len); 100 | len += le32_to_cpu(hdr->dlm_len); 101 | 102 | if (fw->size != len) 103 | goto error; 104 | 105 | val = le16_to_cpu(hdr->fw_ver); 106 | dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", 107 | (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); 108 | 109 | val = le16_to_cpu(hdr->build_ver); 110 | dev_info(dev->mt76.dev, "Build: %x\n", val); 111 | dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); 112 | 113 | cur = (__le32 *)(fw->data + sizeof(*hdr)); 114 | len = le32_to_cpu(hdr->ilm_len); 115 | 116 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET); 117 | mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len); 118 | 119 | cur += len / sizeof(*cur); 120 | len = le32_to_cpu(hdr->dlm_len); 121 | 122 | if (mt76xx_rev(dev) >= MT76XX_REV_E3) 123 | offset = MT_MCU_DLM_ADDR_E3; 124 | else 125 | offset = MT_MCU_DLM_ADDR; 126 | 127 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); 128 | mt76_wr_copy(dev, offset, cur, len); 129 | 130 | mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); 131 | 132 | val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); 133 | if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) 134 | mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); 135 | 136 | /* trigger firmware */ 137 | mt76_wr(dev, MT_MCU_INT_LEVEL, 2); 138 | if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) { 139 | dev_err(dev->mt76.dev, "Firmware failed to start\n"); 140 | release_firmware(fw); 141 | return -ETIMEDOUT; 142 | } 143 | 144 | mt76x02_set_ethtool_fwver(dev, hdr); 145 | dev_info(dev->mt76.dev, "Firmware running!\n"); 146 | 147 | release_firmware(fw); 148 | 149 | return ret; 150 | 151 | error: 152 | dev_err(dev->mt76.dev, "Invalid firmware\n"); 153 | release_firmware(fw); 154 | return -ENOENT; 155 | } 156 | 157 | static int 158 | mt76pci_mcu_restart(struct mt76_dev *mdev) 159 | { 160 | struct mt76x02_dev *dev; 161 | int ret; 162 | 163 | dev = container_of(mdev, struct mt76x02_dev, mt76); 164 | 165 | mt76x02_mcu_cleanup(dev); 166 | mt76x2_mac_reset(dev, true); 167 | 168 | ret = mt76pci_load_firmware(dev); 169 | if (ret) 170 | return ret; 171 | 172 | mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); 173 | 174 | return 0; 175 | } 176 | 177 | int mt76x2_mcu_init(struct mt76x02_dev *dev) 178 | { 179 | static const struct mt76_mcu_ops mt76x2_mcu_ops = { 180 | .mcu_restart = mt76pci_mcu_restart, 181 | .mcu_send_msg = mt76x02_mcu_msg_send, 182 | .mcu_parse_response = mt76x02_mcu_parse_response, 183 | }; 184 | int ret; 185 | 186 | dev->mt76.mcu_ops = &mt76x2_mcu_ops; 187 | 188 | ret = mt76pci_load_rom_patch(dev); 189 | if (ret) 190 | return ret; 191 | 192 | ret = mt76pci_load_firmware(dev); 193 | if (ret) 194 | return ret; 195 | 196 | mt76x02_mcu_function_select(dev, Q_SELECT, 1); 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /mt76x2/usb.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "../mt76x02_usb.h" 10 | #include "mt76x2u.h" 11 | 12 | static const struct usb_device_id mt76x2u_device_table[] = { 13 | { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ 14 | { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ 15 | { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ 16 | { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ 17 | { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ 18 | { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ 19 | { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ 20 | { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ 21 | { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ 22 | { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ 23 | { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ 24 | { }, 25 | }; 26 | 27 | static int mt76x2u_probe(struct usb_interface *intf, 28 | const struct usb_device_id *id) 29 | { 30 | static const struct mt76_driver_ops drv_ops = { 31 | .drv_flags = MT_DRV_SW_RX_AIRTIME, 32 | .survey_flags = SURVEY_INFO_TIME_TX, 33 | .update_survey = mt76x02_update_channel, 34 | .tx_prepare_skb = mt76x02u_tx_prepare_skb, 35 | .tx_complete_skb = mt76x02u_tx_complete_skb, 36 | .tx_status_data = mt76x02_tx_status_data, 37 | .rx_skb = mt76x02_queue_rx_skb, 38 | .sta_ps = mt76x02_sta_ps, 39 | .sta_add = mt76x02_sta_add, 40 | .sta_remove = mt76x02_sta_remove, 41 | }; 42 | struct usb_device *udev = interface_to_usbdev(intf); 43 | struct mt76x02_dev *dev; 44 | struct mt76_dev *mdev; 45 | int err; 46 | 47 | mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, 48 | &drv_ops); 49 | if (!mdev) 50 | return -ENOMEM; 51 | 52 | dev = container_of(mdev, struct mt76x02_dev, mt76); 53 | 54 | udev = usb_get_dev(udev); 55 | usb_reset_device(udev); 56 | 57 | usb_set_intfdata(intf, dev); 58 | 59 | mt76x02u_init_mcu(mdev); 60 | err = mt76u_init(mdev, intf, false); 61 | if (err < 0) 62 | goto err; 63 | 64 | mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 65 | dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 66 | if (!is_mt76x2(dev)) { 67 | err = -ENODEV; 68 | goto err; 69 | } 70 | 71 | err = mt76x2u_register_device(dev); 72 | if (err < 0) 73 | goto err; 74 | 75 | return 0; 76 | 77 | err: 78 | mt76u_queues_deinit(&dev->mt76); 79 | mt76_free_device(&dev->mt76); 80 | usb_set_intfdata(intf, NULL); 81 | usb_put_dev(udev); 82 | 83 | return err; 84 | } 85 | 86 | static void mt76x2u_disconnect(struct usb_interface *intf) 87 | { 88 | struct usb_device *udev = interface_to_usbdev(intf); 89 | struct mt76x02_dev *dev = usb_get_intfdata(intf); 90 | struct ieee80211_hw *hw = mt76_hw(dev); 91 | 92 | set_bit(MT76_REMOVED, &dev->mphy.state); 93 | ieee80211_unregister_hw(hw); 94 | mt76x2u_cleanup(dev); 95 | mt76_free_device(&dev->mt76); 96 | usb_set_intfdata(intf, NULL); 97 | usb_put_dev(udev); 98 | } 99 | 100 | static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, 101 | pm_message_t state) 102 | { 103 | struct mt76x02_dev *dev = usb_get_intfdata(intf); 104 | 105 | mt76u_stop_rx(&dev->mt76); 106 | 107 | return 0; 108 | } 109 | 110 | static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) 111 | { 112 | struct mt76x02_dev *dev = usb_get_intfdata(intf); 113 | int err; 114 | 115 | err = mt76u_resume_rx(&dev->mt76); 116 | if (err < 0) 117 | goto err; 118 | 119 | err = mt76x2u_init_hardware(dev); 120 | if (err < 0) 121 | goto err; 122 | 123 | return 0; 124 | 125 | err: 126 | mt76x2u_cleanup(dev); 127 | return err; 128 | } 129 | 130 | MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); 131 | MODULE_FIRMWARE(MT7662_FIRMWARE); 132 | MODULE_FIRMWARE(MT7662_ROM_PATCH); 133 | 134 | static struct usb_driver mt76x2u_driver = { 135 | .name = KBUILD_MODNAME, 136 | .id_table = mt76x2u_device_table, 137 | .probe = mt76x2u_probe, 138 | .disconnect = mt76x2u_disconnect, 139 | #ifdef CONFIG_PM 140 | .suspend = mt76x2u_suspend, 141 | .resume = mt76x2u_resume, 142 | .reset_resume = mt76x2u_resume, 143 | #endif /* CONFIG_PM */ 144 | .soft_unbind = 1, 145 | .disable_hub_initiated_lpm = 1, 146 | }; 147 | module_usb_driver(mt76x2u_driver); 148 | 149 | MODULE_AUTHOR("Lorenzo Bianconi "); 150 | MODULE_LICENSE("Dual BSD/GPL"); 151 | -------------------------------------------------------------------------------- /mt76x2/usb_mac.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #include "mt76x2u.h" 7 | #include "eeprom.h" 8 | 9 | static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) 10 | { 11 | s8 offset = 0; 12 | u16 eep_val; 13 | 14 | eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2); 15 | 16 | offset = eep_val & 0x7f; 17 | if ((eep_val & 0xff) == 0xff) 18 | offset = 0; 19 | else if (eep_val & 0x80) 20 | offset = 0 - offset; 21 | 22 | eep_val >>= 8; 23 | if (eep_val == 0x00 || eep_val == 0xff) { 24 | eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1); 25 | eep_val &= 0xff; 26 | 27 | if (eep_val == 0x00 || eep_val == 0xff) 28 | eep_val = 0x14; 29 | } 30 | 31 | eep_val &= 0x7f; 32 | mt76_rmw_field(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL5), 33 | MT_XO_CTRL5_C2_VAL, eep_val + offset); 34 | mt76_set(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL6), MT_XO_CTRL6_C2_CTRL); 35 | 36 | mt76_wr(dev, 0x504, 0x06000000); 37 | mt76_wr(dev, 0x50c, 0x08800000); 38 | mdelay(5); 39 | mt76_wr(dev, 0x504, 0x0); 40 | 41 | /* decrease SIFS from 16us to 13us */ 42 | mt76_rmw_field(dev, MT_XIFS_TIME_CFG, 43 | MT_XIFS_TIME_CFG_OFDM_SIFS, 0xd); 44 | mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, MT_BKOFF_SLOT_CFG_CC_DELAY, 1); 45 | 46 | /* init fce */ 47 | mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); 48 | 49 | eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); 50 | switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { 51 | case 0: 52 | mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); 53 | break; 54 | case 1: 55 | mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); 56 | break; 57 | default: 58 | break; 59 | } 60 | } 61 | 62 | int mt76x2u_mac_reset(struct mt76x02_dev *dev) 63 | { 64 | mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5)); 65 | 66 | /* init pbf regs */ 67 | mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); 68 | mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); 69 | 70 | mt76_write_mac_initvals(dev); 71 | 72 | mt76_wr(dev, MT_TX_LINK_CFG, 0x1020); 73 | mt76_wr(dev, MT_AUTO_RSP_CFG, 0x13); 74 | mt76_wr(dev, MT_MAX_LEN_CFG, 0x2f00); 75 | 76 | mt76_wr(dev, MT_WMM_AIFSN, 0x2273); 77 | mt76_wr(dev, MT_WMM_CWMIN, 0x2344); 78 | mt76_wr(dev, MT_WMM_CWMAX, 0x34aa); 79 | 80 | mt76_clear(dev, MT_MAC_SYS_CTRL, 81 | MT_MAC_SYS_CTRL_RESET_CSR | 82 | MT_MAC_SYS_CTRL_RESET_BBP); 83 | 84 | if (is_mt7612(dev)) 85 | mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); 86 | 87 | mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); 88 | mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); 89 | 90 | mt76x2u_mac_fixup_xtal(dev); 91 | 92 | return 0; 93 | } 94 | 95 | int mt76x2u_mac_stop(struct mt76x02_dev *dev) 96 | { 97 | int i, count = 0, val; 98 | bool stopped = false; 99 | u32 rts_cfg; 100 | 101 | if (test_bit(MT76_REMOVED, &dev->mphy.state)) 102 | return -EIO; 103 | 104 | rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); 105 | mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); 106 | 107 | mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); 108 | mt76_clear(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN); 109 | 110 | /* wait tx dma to stop */ 111 | for (i = 0; i < 2000; i++) { 112 | val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); 113 | if (!(val & MT_USB_DMA_CFG_TX_BUSY) && i > 10) 114 | break; 115 | usleep_range(50, 100); 116 | } 117 | 118 | /* page count on TxQ */ 119 | for (i = 0; i < 200; i++) { 120 | if (!(mt76_rr(dev, 0x0438) & 0xffffffff) && 121 | !(mt76_rr(dev, 0x0a30) & 0x000000ff) && 122 | !(mt76_rr(dev, 0x0a34) & 0xff00ff00)) 123 | break; 124 | usleep_range(10, 20); 125 | } 126 | 127 | /* disable tx-rx */ 128 | mt76_clear(dev, MT_MAC_SYS_CTRL, 129 | MT_MAC_SYS_CTRL_ENABLE_RX | 130 | MT_MAC_SYS_CTRL_ENABLE_TX); 131 | 132 | /* Wait for MAC to become idle */ 133 | for (i = 0; i < 1000; i++) { 134 | if (!(mt76_rr(dev, MT_MAC_STATUS) & MT_MAC_STATUS_TX) && 135 | !mt76_rr(dev, MT_BBP(IBI, 12))) { 136 | stopped = true; 137 | break; 138 | } 139 | usleep_range(10, 20); 140 | } 141 | 142 | if (!stopped) { 143 | mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); 144 | mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); 145 | 146 | mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); 147 | mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); 148 | } 149 | 150 | /* page count on RxQ */ 151 | for (i = 0; i < 200; i++) { 152 | if (!(mt76_rr(dev, 0x0430) & 0x00ff0000) && 153 | !(mt76_rr(dev, 0x0a30) & 0xffffffff) && 154 | !(mt76_rr(dev, 0x0a34) & 0xffffffff) && 155 | ++count > 10) 156 | break; 157 | msleep(50); 158 | } 159 | 160 | if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 2000)) 161 | dev_warn(dev->mt76.dev, "MAC RX failed to stop\n"); 162 | 163 | /* wait rx dma to stop */ 164 | for (i = 0; i < 2000; i++) { 165 | val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); 166 | if (!(val & MT_USB_DMA_CFG_RX_BUSY) && i > 10) 167 | break; 168 | usleep_range(50, 100); 169 | } 170 | 171 | mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); 172 | 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /mt76x2/usb_main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #include "mt76x2u.h" 7 | #include "../mt76x02_usb.h" 8 | 9 | static int mt76x2u_start(struct ieee80211_hw *hw) 10 | { 11 | struct mt76x02_dev *dev = hw->priv; 12 | int ret; 13 | 14 | ret = mt76x02u_mac_start(dev); 15 | if (ret) 16 | return ret; 17 | 18 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, 19 | MT_MAC_WORK_INTERVAL); 20 | set_bit(MT76_STATE_RUNNING, &dev->mphy.state); 21 | 22 | return 0; 23 | } 24 | 25 | static void mt76x2u_stop(struct ieee80211_hw *hw) 26 | { 27 | struct mt76x02_dev *dev = hw->priv; 28 | 29 | clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); 30 | mt76u_stop_tx(&dev->mt76); 31 | mt76x2u_stop_hw(dev); 32 | } 33 | 34 | static int 35 | mt76x2u_set_channel(struct mt76x02_dev *dev, 36 | struct cfg80211_chan_def *chandef) 37 | { 38 | int err; 39 | 40 | cancel_delayed_work_sync(&dev->cal_work); 41 | mt76x02_pre_tbtt_enable(dev, false); 42 | 43 | mutex_lock(&dev->mt76.mutex); 44 | set_bit(MT76_RESET, &dev->mphy.state); 45 | 46 | mt76_set_channel(&dev->mphy); 47 | 48 | mt76x2_mac_stop(dev, false); 49 | 50 | err = mt76x2u_phy_set_channel(dev, chandef); 51 | 52 | mt76x02_mac_cc_reset(dev); 53 | mt76x2_mac_resume(dev); 54 | 55 | clear_bit(MT76_RESET, &dev->mphy.state); 56 | mutex_unlock(&dev->mt76.mutex); 57 | 58 | mt76x02_pre_tbtt_enable(dev, true); 59 | mt76_txq_schedule_all(&dev->mphy); 60 | 61 | return err; 62 | } 63 | 64 | static int 65 | mt76x2u_config(struct ieee80211_hw *hw, u32 changed) 66 | { 67 | struct mt76x02_dev *dev = hw->priv; 68 | int err = 0; 69 | 70 | mutex_lock(&dev->mt76.mutex); 71 | 72 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 73 | if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) 74 | dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; 75 | else 76 | dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; 77 | mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 78 | } 79 | 80 | if (changed & IEEE80211_CONF_CHANGE_POWER) { 81 | struct mt76_phy *mphy = &dev->mphy; 82 | 83 | dev->txpower_conf = hw->conf.power_level * 2; 84 | dev->txpower_conf = mt76_get_sar_power(mphy, 85 | mphy->chandef.chan, 86 | dev->txpower_conf); 87 | /* convert to per-chain power for 2x2 devices */ 88 | dev->txpower_conf -= 6; 89 | 90 | if (test_bit(MT76_STATE_RUNNING, &mphy->state)) 91 | mt76x2_phy_set_txpower(dev); 92 | } 93 | 94 | mutex_unlock(&dev->mt76.mutex); 95 | 96 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 97 | ieee80211_stop_queues(hw); 98 | err = mt76x2u_set_channel(dev, &hw->conf.chandef); 99 | ieee80211_wake_queues(hw); 100 | } 101 | 102 | return err; 103 | } 104 | 105 | const struct ieee80211_ops mt76x2u_ops = { 106 | .tx = mt76x02_tx, 107 | .start = mt76x2u_start, 108 | .stop = mt76x2u_stop, 109 | .add_interface = mt76x02_add_interface, 110 | .remove_interface = mt76x02_remove_interface, 111 | .sta_state = mt76_sta_state, 112 | .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 113 | .set_key = mt76x02_set_key, 114 | .ampdu_action = mt76x02_ampdu_action, 115 | .config = mt76x2u_config, 116 | .wake_tx_queue = mt76_wake_tx_queue, 117 | .bss_info_changed = mt76x02_bss_info_changed, 118 | .configure_filter = mt76x02_configure_filter, 119 | .conf_tx = mt76x02_conf_tx, 120 | .sw_scan_start = mt76_sw_scan, 121 | .sw_scan_complete = mt76x02_sw_scan_complete, 122 | .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, 123 | .get_txpower = mt76_get_txpower, 124 | .get_survey = mt76_get_survey, 125 | .set_tim = mt76_set_tim, 126 | .release_buffered_frames = mt76_release_buffered_frames, 127 | .get_antenna = mt76_get_antenna, 128 | .set_sar_specs = mt76x2_set_sar_specs, 129 | }; 130 | -------------------------------------------------------------------------------- /mt7915/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: ISC 2 | config MT7915E 3 | tristate "MediaTek MT7915E (PCIe) support" 4 | select MT76_CORE 5 | depends on MAC80211 6 | depends on PCI 7 | help 8 | This adds support for MT7915-based wireless PCIe devices, 9 | which support concurrent dual-band operation at both 5GHz 10 | and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels, 11 | OFDMA, spatial reuse and dual carrier modulation. 12 | 13 | To compile this driver as a module, choose M here. 14 | -------------------------------------------------------------------------------- /mt7915/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: ISC 2 | 3 | obj-$(CONFIG_MT7915E) += mt7915e.o 4 | 5 | mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \ 6 | debugfs.o mmio.o 7 | 8 | mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o 9 | -------------------------------------------------------------------------------- /mt7915/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #ifndef __MT7915_EEPROM_H 5 | #define __MT7915_EEPROM_H 6 | 7 | #include "mt7915.h" 8 | 9 | struct cal_data { 10 | u8 count; 11 | u16 offset[60]; 12 | }; 13 | 14 | enum mt7915_eeprom_field { 15 | MT_EE_CHIP_ID = 0x000, 16 | MT_EE_VERSION = 0x002, 17 | MT_EE_MAC_ADDR = 0x004, 18 | MT_EE_MAC_ADDR2 = 0x00a, 19 | MT_EE_DDIE_FT_VERSION = 0x050, 20 | MT_EE_DO_PRE_CAL = 0x062, 21 | MT_EE_WIFI_CONF = 0x190, 22 | MT_EE_RATE_DELTA_2G = 0x252, 23 | MT_EE_RATE_DELTA_5G = 0x29d, 24 | MT_EE_TX0_POWER_2G = 0x2fc, 25 | MT_EE_TX0_POWER_5G = 0x34b, 26 | MT_EE_ADIE_FT_VERSION = 0x9a0, 27 | 28 | __MT_EE_MAX = 0xe00, 29 | /* 0xe10 ~ 0x5780 used to save group cal data */ 30 | MT_EE_PRECAL = 0xe10 31 | }; 32 | 33 | #define MT_EE_WIFI_CAL_GROUP BIT(0) 34 | #define MT_EE_WIFI_CAL_DPD GENMASK(2, 1) 35 | #define MT_EE_CAL_UNIT 1024 36 | #define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16) 37 | #define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT) 38 | 39 | #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) 40 | #define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6) 41 | #define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6) 42 | #define MT_EE_WIFI_CONF3_TX_PATH_B0 GENMASK(1, 0) 43 | #define MT_EE_WIFI_CONF3_TX_PATH_B1 GENMASK(5, 4) 44 | #define MT_EE_WIFI_CONF7_TSSI0_2G BIT(0) 45 | #define MT_EE_WIFI_CONF7_TSSI0_5G BIT(2) 46 | #define MT_EE_WIFI_CONF7_TSSI1_5G BIT(4) 47 | 48 | #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0) 49 | #define MT_EE_RATE_DELTA_SIGN BIT(6) 50 | #define MT_EE_RATE_DELTA_EN BIT(7) 51 | 52 | enum mt7915_eeprom_band { 53 | MT_EE_BAND_SEL_DEFAULT, 54 | MT_EE_BAND_SEL_5GHZ, 55 | MT_EE_BAND_SEL_2GHZ, 56 | MT_EE_BAND_SEL_DUAL, 57 | }; 58 | 59 | enum mt7915_sku_rate_group { 60 | SKU_CCK, 61 | SKU_OFDM, 62 | SKU_HT_BW20, 63 | SKU_HT_BW40, 64 | SKU_VHT_BW20, 65 | SKU_VHT_BW40, 66 | SKU_VHT_BW80, 67 | SKU_VHT_BW160, 68 | SKU_HE_RU26, 69 | SKU_HE_RU52, 70 | SKU_HE_RU106, 71 | SKU_HE_RU242, 72 | SKU_HE_RU484, 73 | SKU_HE_RU996, 74 | SKU_HE_RU2x996, 75 | MAX_SKU_RATE_GROUP_NUM, 76 | }; 77 | 78 | static inline int 79 | mt7915_get_channel_group(int channel) 80 | { 81 | if (channel >= 184 && channel <= 196) 82 | return 0; 83 | if (channel <= 48) 84 | return 1; 85 | if (channel <= 64) 86 | return 2; 87 | if (channel <= 96) 88 | return 3; 89 | if (channel <= 112) 90 | return 4; 91 | if (channel <= 128) 92 | return 5; 93 | if (channel <= 144) 94 | return 6; 95 | return 7; 96 | } 97 | 98 | static inline bool 99 | mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) 100 | { 101 | u8 *eep = dev->mt76.eeprom.data; 102 | u8 val = eep[MT_EE_WIFI_CONF + 7]; 103 | 104 | if (band == NL80211_BAND_2GHZ) 105 | return val & MT_EE_WIFI_CONF7_TSSI0_2G; 106 | 107 | if (dev->dbdc_support) 108 | return val & MT_EE_WIFI_CONF7_TSSI1_5G; 109 | else 110 | return val & MT_EE_WIFI_CONF7_TSSI0_5G; 111 | } 112 | 113 | extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM]; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /mt7915/testmode.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #ifndef __MT7915_TESTMODE_H 5 | #define __MT7915_TESTMODE_H 6 | 7 | struct mt7915_tm_trx { 8 | u8 type; 9 | u8 enable; 10 | u8 band; 11 | u8 rsv; 12 | }; 13 | 14 | struct mt7915_tm_freq_offset { 15 | u8 band; 16 | __le32 freq_offset; 17 | }; 18 | 19 | struct mt7915_tm_slot_time { 20 | u8 slot_time; 21 | u8 sifs; 22 | u8 rifs; 23 | u8 _rsv; 24 | __le16 eifs; 25 | u8 band; 26 | u8 _rsv1[5]; 27 | }; 28 | 29 | struct mt7915_tm_clean_txq { 30 | bool sta_pause; 31 | u8 wcid; /* 256 sta */ 32 | u8 band; 33 | u8 rsv; 34 | }; 35 | 36 | struct mt7915_tm_cmd { 37 | u8 testmode_en; 38 | u8 param_idx; 39 | u8 _rsv[2]; 40 | union { 41 | __le32 data; 42 | struct mt7915_tm_trx trx; 43 | struct mt7915_tm_freq_offset freq; 44 | struct mt7915_tm_slot_time slot; 45 | struct mt7915_tm_clean_txq clean; 46 | u8 test[72]; 47 | } param; 48 | } __packed; 49 | 50 | enum { 51 | TM_MAC_TX = 1, 52 | TM_MAC_RX, 53 | TM_MAC_TXRX, 54 | TM_MAC_TXRX_RXV, 55 | TM_MAC_RXV, 56 | TM_MAC_RX_RXV, 57 | }; 58 | 59 | struct tm_tx_cont { 60 | u8 control_ch; 61 | u8 center_ch; 62 | u8 bw; 63 | u8 tx_ant; 64 | __le16 rateval; 65 | u8 band; 66 | u8 txfd_mode; 67 | }; 68 | 69 | struct mt7915_tm_rf_test { 70 | u8 action; 71 | u8 icap_len; 72 | u8 _rsv[2]; 73 | union { 74 | __le32 op_mode; 75 | __le32 freq; 76 | 77 | struct { 78 | __le32 func_idx; 79 | union { 80 | __le32 func_data; 81 | __le32 cal_dump; 82 | 83 | struct tm_tx_cont tx_cont; 84 | 85 | u8 _pad[80]; 86 | } param; 87 | } rf; 88 | } op; 89 | } __packed; 90 | 91 | enum { 92 | RF_OPER_NORMAL, 93 | RF_OPER_RF_TEST, 94 | RF_OPER_ICAP, 95 | RF_OPER_ICAP_OVERLAP, 96 | RF_OPER_WIFI_SPECTRUM, 97 | }; 98 | 99 | enum { 100 | TAM_ARB_OP_MODE_NORMAL = 1, 101 | TAM_ARB_OP_MODE_TEST, 102 | TAM_ARB_OP_MODE_FORCE_SU = 5, 103 | }; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /mt7921/Kconfig: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: ISC 2 | config MT7921_COMMON 3 | tristate 4 | select MT76_CONNAC_LIB 5 | select WANT_DEV_COREDUMP 6 | 7 | config MT7921E 8 | tristate "MediaTek MT7921E (PCIe) support" 9 | select MT7921_COMMON 10 | depends on MAC80211 11 | depends on PCI 12 | help 13 | This adds support for MT7921E 802.11ax 2x2:2SS wireless devices. 14 | 15 | To compile this driver as a module, choose M here. 16 | 17 | config MT7921S 18 | tristate "MediaTek MT7921S (SDIO) support" 19 | select MT76_SDIO 20 | select MT7921_COMMON 21 | depends on MAC80211 22 | depends on MMC 23 | help 24 | This adds support for MT7921S 802.11ax 2x2:2SS wireless devices. 25 | 26 | To compile this driver as a module, choose M here. 27 | -------------------------------------------------------------------------------- /mt7921/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: ISC 2 | 3 | obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o 4 | obj-$(CONFIG_MT7921E) += mt7921e.o 5 | obj-$(CONFIG_MT7921S) += mt7921s.o 6 | 7 | CFLAGS_trace.o := -I$(src) 8 | 9 | mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o 10 | mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o 11 | mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o 12 | mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o 13 | -------------------------------------------------------------------------------- /mt7921/eeprom.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #ifndef __MT7921_EEPROM_H 5 | #define __MT7921_EEPROM_H 6 | 7 | #include "mt7921.h" 8 | 9 | enum mt7921_eeprom_field { 10 | MT_EE_CHIP_ID = 0x000, 11 | MT_EE_VERSION = 0x002, 12 | MT_EE_MAC_ADDR = 0x004, 13 | MT_EE_WIFI_CONF = 0x07c, 14 | __MT_EE_MAX = 0x3bf 15 | }; 16 | 17 | #define MT_EE_WIFI_CONF_TX_MASK BIT(0) 18 | #define MT_EE_WIFI_CONF_BAND_SEL GENMASK(3, 2) 19 | 20 | enum mt7921_eeprom_band { 21 | MT_EE_NA, 22 | MT_EE_5GHZ, 23 | MT_EE_2GHZ, 24 | MT_EE_DUAL_BAND, 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /mt7921/mcu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. */ 3 | 4 | #ifndef __MT7921_MCU_H 5 | #define __MT7921_MCU_H 6 | 7 | #include "../mt76_connac_mcu.h" 8 | 9 | struct mt7921_mcu_txd { 10 | __le32 txd[8]; 11 | 12 | __le16 len; 13 | __le16 pq_id; 14 | 15 | u8 cid; 16 | u8 pkt_type; 17 | u8 set_query; /* FW don't care */ 18 | u8 seq; 19 | 20 | u8 uc_d2b0_rev; 21 | u8 ext_cid; 22 | u8 s2d_index; 23 | u8 ext_cid_ack; 24 | 25 | u32 reserved[5]; 26 | } __packed __aligned(4); 27 | 28 | /** 29 | * struct mt7921_uni_txd - mcu command descriptor for firmware v3 30 | * @txd: hardware descriptor 31 | * @len: total length not including txd 32 | * @cid: command identifier 33 | * @pkt_type: must be 0xa0 (cmd packet by long format) 34 | * @frag_n: fragment number 35 | * @seq: sequence number 36 | * @checksum: 0 mean there is no checksum 37 | * @s2d_index: index for command source and destination 38 | * Definition | value | note 39 | * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM 40 | * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM 41 | * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA 42 | * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM 43 | * 44 | * @option: command option 45 | * BIT[0]: UNI_CMD_OPT_BIT_ACK 46 | * set to 1 to request a fw reply 47 | * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY 48 | * is set, mcu firmware will send response event EID = 0x01 49 | * (UNI_EVENT_ID_CMD_RESULT) to the host. 50 | * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD 51 | * 0: original command 52 | * 1: unified command 53 | * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY 54 | * 0: QUERY command 55 | * 1: SET command 56 | */ 57 | struct mt7921_uni_txd { 58 | __le32 txd[8]; 59 | 60 | /* DW1 */ 61 | __le16 len; 62 | __le16 cid; 63 | 64 | /* DW2 */ 65 | u8 reserved; 66 | u8 pkt_type; 67 | u8 frag_n; 68 | u8 seq; 69 | 70 | /* DW3 */ 71 | __le16 checksum; 72 | u8 s2d_index; 73 | u8 option; 74 | 75 | /* DW4 */ 76 | u8 reserved2[4]; 77 | } __packed __aligned(4); 78 | 79 | struct mt7921_mcu_tx_done_event { 80 | u8 pid; 81 | u8 status; 82 | __le16 seq; 83 | 84 | u8 wlan_idx; 85 | u8 tx_cnt; 86 | __le16 tx_rate; 87 | 88 | u8 flag; 89 | u8 tid; 90 | u8 rsp_rate; 91 | u8 mcs; 92 | 93 | u8 bw; 94 | u8 tx_pwr; 95 | u8 reason; 96 | u8 rsv0[1]; 97 | 98 | __le32 delay; 99 | __le32 timestamp; 100 | __le32 applied_flag; 101 | u8 txs[28]; 102 | 103 | u8 rsv1[32]; 104 | } __packed; 105 | 106 | /* ext event table */ 107 | enum { 108 | MCU_EXT_EVENT_RATE_REPORT = 0x87, 109 | }; 110 | 111 | struct mt7921_mcu_rxd { 112 | __le32 rxd[6]; 113 | 114 | __le16 len; 115 | __le16 pkt_type_id; 116 | 117 | u8 eid; 118 | u8 seq; 119 | __le16 __rsv; 120 | 121 | u8 ext_eid; 122 | u8 __rsv1[2]; 123 | u8 s2d_index; 124 | }; 125 | 126 | struct mt7921_mcu_eeprom_info { 127 | __le32 addr; 128 | __le32 valid; 129 | u8 data[16]; 130 | } __packed; 131 | 132 | #define MT_RA_RATE_NSS GENMASK(8, 6) 133 | #define MT_RA_RATE_MCS GENMASK(3, 0) 134 | #define MT_RA_RATE_TX_MODE GENMASK(12, 9) 135 | #define MT_RA_RATE_DCM_EN BIT(4) 136 | #define MT_RA_RATE_BW GENMASK(14, 13) 137 | 138 | #define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) 139 | #define MCU_PKT_ID 0xa0 140 | 141 | struct mt7921_mcu_uni_event { 142 | u8 cid; 143 | u8 pad[3]; 144 | __le32 status; /* 0: success, others: fail */ 145 | } __packed; 146 | 147 | enum { 148 | MT_EBF = BIT(0), /* explicit beamforming */ 149 | MT_IBF = BIT(1) /* implicit beamforming */ 150 | }; 151 | 152 | struct mt7921_mcu_reg_event { 153 | __le32 reg; 154 | __le32 val; 155 | } __packed; 156 | 157 | struct mt7921_mcu_ant_id_config { 158 | u8 ant_id[4]; 159 | } __packed; 160 | 161 | struct mt7921_txpwr_req { 162 | u8 ver; 163 | u8 action; 164 | __le16 len; 165 | u8 dbdc_idx; 166 | u8 rsv[3]; 167 | } __packed; 168 | 169 | struct mt7921_txpwr_event { 170 | u8 ver; 171 | u8 action; 172 | __le16 len; 173 | struct mt7921_txpwr txpwr; 174 | } __packed; 175 | 176 | enum { 177 | TM_SWITCH_MODE, 178 | TM_SET_AT_CMD, 179 | TM_QUERY_AT_CMD, 180 | }; 181 | 182 | enum { 183 | MT7921_TM_NORMAL, 184 | MT7921_TM_TESTMODE, 185 | MT7921_TM_ICAP, 186 | MT7921_TM_ICAP_OVERLAP, 187 | MT7921_TM_WIFISPECTRUM, 188 | }; 189 | 190 | struct mt7921_rftest_cmd { 191 | u8 action; 192 | u8 rsv[3]; 193 | __le32 param0; 194 | __le32 param1; 195 | } __packed; 196 | 197 | struct mt7921_rftest_evt { 198 | __le32 param0; 199 | __le32 param1; 200 | } __packed; 201 | #endif 202 | -------------------------------------------------------------------------------- /mt7921/mt7921_trace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2021 Lorenzo Bianconi 4 | */ 5 | 6 | #if !defined(__MT7921_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 7 | #define __MT7921_TRACE_H 8 | 9 | #include 10 | #include "mt7921.h" 11 | 12 | #undef TRACE_SYSTEM 13 | #define TRACE_SYSTEM mt7921 14 | 15 | #define MAXNAME 32 16 | #define DEV_ENTRY __array(char, wiphy_name, 32) 17 | #define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ 18 | wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) 19 | #define DEV_PR_FMT "%s" 20 | #define DEV_PR_ARG __entry->wiphy_name 21 | #define LP_STATE_PR_ARG __entry->lp_state ? "lp ready" : "lp not ready" 22 | 23 | TRACE_EVENT(lp_event, 24 | TP_PROTO(struct mt7921_dev *dev, u8 lp_state), 25 | 26 | TP_ARGS(dev, lp_state), 27 | 28 | TP_STRUCT__entry( 29 | DEV_ENTRY 30 | __field(u8, lp_state) 31 | ), 32 | 33 | TP_fast_assign( 34 | DEV_ASSIGN; 35 | __entry->lp_state = lp_state; 36 | ), 37 | 38 | TP_printk( 39 | DEV_PR_FMT " %s", 40 | DEV_PR_ARG, LP_STATE_PR_ARG 41 | ) 42 | ); 43 | 44 | #endif 45 | 46 | #undef TRACE_INCLUDE_PATH 47 | #define TRACE_INCLUDE_PATH . 48 | #undef TRACE_INCLUDE_FILE 49 | #define TRACE_INCLUDE_FILE mt7921_trace 50 | 51 | #include 52 | -------------------------------------------------------------------------------- /mt7921/pci_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2021 MediaTek Inc. */ 3 | 4 | #include "mt7921.h" 5 | #include "mcu.h" 6 | 7 | int mt7921e_driver_own(struct mt7921_dev *dev) 8 | { 9 | u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); 10 | 11 | mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); 12 | if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, 13 | 0, 500)) { 14 | dev_err(dev->mt76.dev, "Timeout for driver own\n"); 15 | return -EIO; 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | static int 22 | mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 23 | int cmd, int *seq) 24 | { 25 | struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 26 | enum mt76_mcuq_id txq = MT_MCUQ_WM; 27 | int ret; 28 | 29 | ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); 30 | if (ret) 31 | return ret; 32 | 33 | if (cmd == MCU_CMD(FW_SCATTER)) 34 | txq = MT_MCUQ_FWDL; 35 | 36 | return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 37 | } 38 | 39 | int mt7921e_mcu_init(struct mt7921_dev *dev) 40 | { 41 | static const struct mt76_mcu_ops mt7921_mcu_ops = { 42 | .headroom = sizeof(struct mt7921_mcu_txd), 43 | .mcu_skb_send_msg = mt7921_mcu_send_message, 44 | .mcu_parse_response = mt7921_mcu_parse_response, 45 | .mcu_restart = mt7921_mcu_restart, 46 | }; 47 | int err; 48 | 49 | dev->mt76.mcu_ops = &mt7921_mcu_ops; 50 | 51 | err = mt7921e_driver_own(dev); 52 | if (err) 53 | return err; 54 | 55 | err = mt7921_run_firmware(dev); 56 | 57 | mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 58 | 59 | return err; 60 | } 61 | 62 | int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) 63 | { 64 | struct mt76_phy *mphy = &dev->mt76.phy; 65 | struct mt76_connac_pm *pm = &dev->pm; 66 | int i, err = 0; 67 | 68 | for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 69 | mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); 70 | if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 71 | PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) 72 | break; 73 | } 74 | 75 | if (i == MT7921_DRV_OWN_RETRY_COUNT) { 76 | dev_err(dev->mt76.dev, "driver own failed\n"); 77 | err = -EIO; 78 | goto out; 79 | } 80 | 81 | mt7921_wpdma_reinit_cond(dev); 82 | clear_bit(MT76_STATE_PM, &mphy->state); 83 | 84 | pm->stats.last_wake_event = jiffies; 85 | pm->stats.doze_time += pm->stats.last_wake_event - 86 | pm->stats.last_doze_event; 87 | out: 88 | return err; 89 | } 90 | 91 | int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev) 92 | { 93 | struct mt76_phy *mphy = &dev->mt76.phy; 94 | struct mt76_connac_pm *pm = &dev->pm; 95 | int i, err = 0; 96 | 97 | for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { 98 | mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); 99 | if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, 100 | PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) 101 | break; 102 | } 103 | 104 | if (i == MT7921_DRV_OWN_RETRY_COUNT) { 105 | dev_err(dev->mt76.dev, "firmware own failed\n"); 106 | clear_bit(MT76_STATE_PM, &mphy->state); 107 | err = -EIO; 108 | } 109 | 110 | pm->stats.last_doze_event = jiffies; 111 | pm->stats.awake_time += pm->stats.last_doze_event - 112 | pm->stats.last_wake_event; 113 | 114 | return err; 115 | } 116 | -------------------------------------------------------------------------------- /mt7921/sdio_mcu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2021 MediaTek Inc. */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mt7921.h" 10 | #include "../sdio.h" 11 | #include "mac.h" 12 | #include "mcu.h" 13 | #include "regs.h" 14 | 15 | static int 16 | mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 17 | int cmd, int *seq) 18 | { 19 | struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 20 | enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD; 21 | enum mt76_mcuq_id txq = MT_MCUQ_WM; 22 | int ret, pad; 23 | 24 | /* We just return in case firmware assertion to avoid blocking the 25 | * common workqueue to run, for example, the coredump work might be 26 | * blocked by mt7921_mac_work that is excuting register access via sdio 27 | * bus. 28 | */ 29 | if (dev->fw_assert) 30 | return -EBUSY; 31 | 32 | ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); 33 | if (ret) 34 | return ret; 35 | 36 | if (cmd == MCU_CMD(FW_SCATTER)) 37 | type = MT7921_SDIO_FWDL; 38 | 39 | mt7921_skb_add_sdio_hdr(skb, type); 40 | pad = round_up(skb->len, 4) - skb->len; 41 | __skb_put_zero(skb, pad); 42 | 43 | ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 44 | if (ret) 45 | return ret; 46 | 47 | mt76_queue_kick(dev, mdev->q_mcu[txq]); 48 | 49 | return ret; 50 | } 51 | 52 | int mt7921s_mcu_init(struct mt7921_dev *dev) 53 | { 54 | static const struct mt76_mcu_ops mt7921s_mcu_ops = { 55 | .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd), 56 | .tailroom = MT_SDIO_TAIL_SIZE, 57 | .mcu_skb_send_msg = mt7921s_mcu_send_message, 58 | .mcu_parse_response = mt7921_mcu_parse_response, 59 | .mcu_rr = mt76_connac_mcu_reg_rr, 60 | .mcu_wr = mt76_connac_mcu_reg_wr, 61 | }; 62 | int ret; 63 | 64 | mt7921s_mcu_drv_pmctrl(dev); 65 | 66 | dev->mt76.mcu_ops = &mt7921s_mcu_ops; 67 | 68 | ret = mt7921_run_firmware(dev); 69 | if (ret) 70 | return ret; 71 | 72 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 73 | 74 | return 0; 75 | } 76 | 77 | int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) 78 | { 79 | struct sdio_func *func = dev->mt76.sdio.func; 80 | struct mt76_phy *mphy = &dev->mt76.phy; 81 | struct mt76_connac_pm *pm = &dev->pm; 82 | int err = 0; 83 | u32 status; 84 | 85 | sdio_claim_host(func); 86 | 87 | sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 88 | 89 | err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 90 | status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 91 | sdio_release_host(func); 92 | 93 | if (err < 0) { 94 | dev_err(dev->mt76.dev, "driver own failed\n"); 95 | err = -EIO; 96 | goto out; 97 | } 98 | 99 | clear_bit(MT76_STATE_PM, &mphy->state); 100 | 101 | pm->stats.last_wake_event = jiffies; 102 | pm->stats.doze_time += pm->stats.last_wake_event - 103 | pm->stats.last_doze_event; 104 | out: 105 | return err; 106 | } 107 | 108 | int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) 109 | { 110 | struct sdio_func *func = dev->mt76.sdio.func; 111 | struct mt76_phy *mphy = &dev->mt76.phy; 112 | struct mt76_connac_pm *pm = &dev->pm; 113 | int err = 0; 114 | u32 status; 115 | 116 | sdio_claim_host(func); 117 | 118 | sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 119 | 120 | err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 121 | !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 122 | sdio_release_host(func); 123 | 124 | if (err < 0) { 125 | dev_err(dev->mt76.dev, "firmware own failed\n"); 126 | clear_bit(MT76_STATE_PM, &mphy->state); 127 | err = -EIO; 128 | } 129 | 130 | pm->stats.last_doze_event = jiffies; 131 | pm->stats.awake_time += pm->stats.last_doze_event - 132 | pm->stats.last_wake_event; 133 | 134 | return err; 135 | } 136 | -------------------------------------------------------------------------------- /mt7921/testmode.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | 3 | #include "mt7921.h" 4 | #include "mcu.h" 5 | 6 | enum mt7921_testmode_attr { 7 | MT7921_TM_ATTR_UNSPEC, 8 | MT7921_TM_ATTR_SET, 9 | MT7921_TM_ATTR_QUERY, 10 | MT7921_TM_ATTR_RSP, 11 | 12 | /* keep last */ 13 | NUM_MT7921_TM_ATTRS, 14 | MT7921_TM_ATTR_MAX = NUM_MT7921_TM_ATTRS - 1, 15 | }; 16 | 17 | struct mt7921_tm_cmd { 18 | u8 action; 19 | u32 param0; 20 | u32 param1; 21 | }; 22 | 23 | struct mt7921_tm_evt { 24 | u32 param0; 25 | u32 param1; 26 | }; 27 | 28 | static const struct nla_policy mt7921_tm_policy[NUM_MT7921_TM_ATTRS] = { 29 | [MT7921_TM_ATTR_SET] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)), 30 | [MT7921_TM_ATTR_QUERY] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)), 31 | }; 32 | 33 | static int 34 | mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req) 35 | { 36 | struct mt7921_rftest_cmd cmd = { 37 | .action = req->action, 38 | .param0 = cpu_to_le32(req->param0), 39 | .param1 = cpu_to_le32(req->param1), 40 | }; 41 | bool testmode = false, normal = false; 42 | struct mt76_connac_pm *pm = &dev->pm; 43 | struct mt76_phy *phy = &dev->mphy; 44 | int ret = -ENOTCONN; 45 | 46 | mutex_lock(&dev->mt76.mutex); 47 | 48 | if (req->action == TM_SWITCH_MODE) { 49 | if (req->param0 == MT7921_TM_NORMAL) 50 | normal = true; 51 | else 52 | testmode = true; 53 | } 54 | 55 | if (testmode) { 56 | /* Make sure testmode running on full power mode */ 57 | pm->enable = false; 58 | cancel_delayed_work_sync(&pm->ps_work); 59 | cancel_work_sync(&pm->wake_work); 60 | __mt7921_mcu_drv_pmctrl(dev); 61 | 62 | mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter); 63 | phy->test.state = MT76_TM_STATE_ON; 64 | } 65 | 66 | if (!mt76_testmode_enabled(phy)) 67 | goto out; 68 | 69 | ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL), &cmd, 70 | sizeof(cmd), false); 71 | if (ret) 72 | goto out; 73 | 74 | if (normal) { 75 | /* Switch back to the normal world */ 76 | phy->test.state = MT76_TM_STATE_OFF; 77 | pm->enable = true; 78 | } 79 | out: 80 | mutex_unlock(&dev->mt76.mutex); 81 | 82 | return ret; 83 | } 84 | 85 | static int 86 | mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req, 87 | struct mt7921_tm_evt *evt_resp) 88 | { 89 | struct mt7921_rftest_cmd cmd = { 90 | .action = req->action, 91 | .param0 = cpu_to_le32(req->param0), 92 | .param1 = cpu_to_le32(req->param1), 93 | }; 94 | struct mt7921_rftest_evt *evt; 95 | struct sk_buff *skb; 96 | int ret; 97 | 98 | ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL), 99 | &cmd, sizeof(cmd), true, &skb); 100 | if (ret) 101 | goto out; 102 | 103 | evt = (struct mt7921_rftest_evt *)skb->data; 104 | evt_resp->param0 = le32_to_cpu(evt->param0); 105 | evt_resp->param1 = le32_to_cpu(evt->param1); 106 | out: 107 | dev_kfree_skb(skb); 108 | 109 | return ret; 110 | } 111 | 112 | int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 113 | void *data, int len) 114 | { 115 | struct nlattr *tb[NUM_MT76_TM_ATTRS]; 116 | struct mt76_phy *mphy = hw->priv; 117 | struct mt7921_phy *phy = mphy->priv; 118 | int err; 119 | 120 | if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || 121 | !(hw->conf.flags & IEEE80211_CONF_MONITOR)) 122 | return -ENOTCONN; 123 | 124 | err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, 125 | mt76_tm_policy, NULL); 126 | if (err) 127 | return err; 128 | 129 | if (tb[MT76_TM_ATTR_DRV_DATA]) { 130 | struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data; 131 | int ret; 132 | 133 | data = tb[MT76_TM_ATTR_DRV_DATA]; 134 | ret = nla_parse_nested_deprecated(drv_tb, 135 | MT7921_TM_ATTR_MAX, 136 | data, mt7921_tm_policy, 137 | NULL); 138 | if (ret) 139 | return ret; 140 | 141 | data = drv_tb[MT7921_TM_ATTR_SET]; 142 | if (data) 143 | return mt7921_tm_set(phy->dev, nla_data(data)); 144 | } 145 | 146 | return -EINVAL; 147 | } 148 | 149 | int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, 150 | struct netlink_callback *cb, void *data, int len) 151 | { 152 | struct nlattr *tb[NUM_MT76_TM_ATTRS]; 153 | struct mt76_phy *mphy = hw->priv; 154 | struct mt7921_phy *phy = mphy->priv; 155 | int err; 156 | 157 | if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || 158 | !(hw->conf.flags & IEEE80211_CONF_MONITOR) || 159 | !mt76_testmode_enabled(mphy)) 160 | return -ENOTCONN; 161 | 162 | if (cb->args[2]++ > 0) 163 | return -ENOENT; 164 | 165 | err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, 166 | mt76_tm_policy, NULL); 167 | if (err) 168 | return err; 169 | 170 | if (tb[MT76_TM_ATTR_DRV_DATA]) { 171 | struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data; 172 | int ret; 173 | 174 | data = tb[MT76_TM_ATTR_DRV_DATA]; 175 | ret = nla_parse_nested_deprecated(drv_tb, 176 | MT7921_TM_ATTR_MAX, 177 | data, mt7921_tm_policy, 178 | NULL); 179 | if (ret) 180 | return ret; 181 | 182 | data = drv_tb[MT7921_TM_ATTR_QUERY]; 183 | if (data) { 184 | struct mt7921_tm_evt evt_resp; 185 | 186 | err = mt7921_tm_query(phy->dev, nla_data(data), 187 | &evt_resp); 188 | if (err) 189 | return err; 190 | 191 | return nla_put(msg, MT7921_TM_ATTR_RSP, 192 | sizeof(evt_resp), &evt_resp); 193 | } 194 | } 195 | 196 | return -EINVAL; 197 | } 198 | -------------------------------------------------------------------------------- /mt7921/trace.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2021 Lorenzo Bianconi 4 | */ 5 | 6 | #include 7 | 8 | #ifndef __CHECKER__ 9 | #define CREATE_TRACE_POINTS 10 | #include "mt7921_trace.h" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /pci.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2019 Lorenzo Bianconi 4 | */ 5 | 6 | #include "mt76.h" 7 | #include 8 | 9 | void mt76_pci_disable_aspm(struct pci_dev *pdev) 10 | { 11 | struct pci_dev *parent = pdev->bus->self; 12 | u16 aspm_conf, parent_aspm_conf = 0; 13 | 14 | pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); 15 | aspm_conf &= PCI_EXP_LNKCTL_ASPMC; 16 | if (parent) { 17 | pcie_capability_read_word(parent, PCI_EXP_LNKCTL, 18 | &parent_aspm_conf); 19 | parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; 20 | } 21 | 22 | if (!aspm_conf && (!parent || !parent_aspm_conf)) { 23 | /* aspm already disabled */ 24 | return; 25 | } 26 | 27 | dev_info(&pdev->dev, "disabling ASPM %s %s\n", 28 | (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", 29 | (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); 30 | 31 | if (IS_ENABLED(CONFIG_PCIEASPM)) { 32 | int err; 33 | 34 | err = pci_disable_link_state(pdev, aspm_conf); 35 | if (!err) 36 | return; 37 | } 38 | 39 | /* both device and parent should have the same ASPM setting. 40 | * disable ASPM in downstream component first and then upstream. 41 | */ 42 | pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf); 43 | if (parent) 44 | pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, 45 | aspm_conf); 46 | } 47 | EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm); 48 | -------------------------------------------------------------------------------- /sdio.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* Copyright (C) 2020 MediaTek Inc. 3 | * 4 | * Author: Sean Wang 5 | */ 6 | 7 | #ifndef __MT76S_H 8 | #define __MT76S_H 9 | 10 | #define MT_PSE_PAGE_SZ 128 11 | 12 | #define MCR_WCIR 0x0000 13 | #define MCR_WHLPCR 0x0004 14 | #define WHLPCR_FW_OWN_REQ_CLR BIT(9) 15 | #define WHLPCR_FW_OWN_REQ_SET BIT(8) 16 | #define WHLPCR_IS_DRIVER_OWN BIT(8) 17 | #define WHLPCR_INT_EN_CLR BIT(1) 18 | #define WHLPCR_INT_EN_SET BIT(0) 19 | 20 | #define MCR_WSDIOCSR 0x0008 21 | #define MCR_WHCR 0x000C 22 | #define W_INT_CLR_CTRL BIT(1) 23 | #define RECV_MAILBOX_RD_CLR_EN BIT(2) 24 | #define WF_SYS_RSTB BIT(4) /* supported in CONNAC2 */ 25 | #define WF_WHOLE_PATH_RSTB BIT(5) /* supported in CONNAC2 */ 26 | #define WF_SDIO_WF_PATH_RSTB BIT(6) /* supported in CONNAC2 */ 27 | #define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) 28 | #define MAX_HIF_RX_LEN_NUM_CONNAC2 GENMASK(14, 8) /* supported in CONNAC2 */ 29 | #define WF_RST_DONE BIT(15) /* supported in CONNAC2 */ 30 | #define RX_ENHANCE_MODE BIT(16) 31 | 32 | #define MCR_WHISR 0x0010 33 | #define MCR_WHIER 0x0014 34 | #define WHIER_D2H_SW_INT GENMASK(31, 8) 35 | #define WHIER_FW_OWN_BACK_INT_EN BIT(7) 36 | #define WHIER_ABNORMAL_INT_EN BIT(6) 37 | #define WHIER_WDT_INT_EN BIT(5) /* supported in CONNAC2 */ 38 | #define WHIER_RX1_DONE_INT_EN BIT(2) 39 | #define WHIER_RX0_DONE_INT_EN BIT(1) 40 | #define WHIER_TX_DONE_INT_EN BIT(0) 41 | #define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ 42 | WHIER_RX1_DONE_INT_EN | \ 43 | WHIER_TX_DONE_INT_EN | \ 44 | WHIER_ABNORMAL_INT_EN | \ 45 | WHIER_D2H_SW_INT) 46 | 47 | #define MCR_WASR 0x0020 48 | #define MCR_WSICR 0x0024 49 | #define MCR_WTSR0 0x0028 50 | #define TQ0_CNT GENMASK(7, 0) 51 | #define TQ1_CNT GENMASK(15, 8) 52 | #define TQ2_CNT GENMASK(23, 16) 53 | #define TQ3_CNT GENMASK(31, 24) 54 | 55 | #define MCR_WTSR1 0x002c 56 | #define TQ4_CNT GENMASK(7, 0) 57 | #define TQ5_CNT GENMASK(15, 8) 58 | #define TQ6_CNT GENMASK(23, 16) 59 | #define TQ7_CNT GENMASK(31, 24) 60 | 61 | #define MCR_WTDR1 0x0034 62 | #define MCR_WRDR0 0x0050 63 | #define MCR_WRDR1 0x0054 64 | #define MCR_WRDR(p) (0x0050 + 4 * (p)) 65 | #define MCR_H2DSM0R 0x0070 66 | #define H2D_SW_INT_READ BIT(16) 67 | #define H2D_SW_INT_WRITE BIT(17) 68 | 69 | #define MCR_H2DSM1R 0x0074 70 | #define MCR_D2HRM0R 0x0078 71 | #define MCR_D2HRM1R 0x007c 72 | #define MCR_D2HRM2R 0x0080 73 | #define MCR_WRPLR 0x0090 74 | #define RX0_PACKET_LENGTH GENMASK(15, 0) 75 | #define RX1_PACKET_LENGTH GENMASK(31, 16) 76 | 77 | #define MCR_WTMDR 0x00b0 78 | #define MCR_WTMCR 0x00b4 79 | #define MCR_WTMDPCR0 0x00b8 80 | #define MCR_WTMDPCR1 0x00bc 81 | #define MCR_WPLRCR 0x00d4 82 | #define MCR_WSR 0x00D8 83 | #define MCR_CLKIOCR 0x0100 84 | #define MCR_CMDIOCR 0x0104 85 | #define MCR_DAT0IOCR 0x0108 86 | #define MCR_DAT1IOCR 0x010C 87 | #define MCR_DAT2IOCR 0x0110 88 | #define MCR_DAT3IOCR 0x0114 89 | #define MCR_CLKDLYCR 0x0118 90 | #define MCR_CMDDLYCR 0x011C 91 | #define MCR_ODATDLYCR 0x0120 92 | #define MCR_IDATDLYCR1 0x0124 93 | #define MCR_IDATDLYCR2 0x0128 94 | #define MCR_ILCHCR 0x012C 95 | #define MCR_WTQCR0 0x0130 96 | #define MCR_WTQCR1 0x0134 97 | #define MCR_WTQCR2 0x0138 98 | #define MCR_WTQCR3 0x013C 99 | #define MCR_WTQCR4 0x0140 100 | #define MCR_WTQCR5 0x0144 101 | #define MCR_WTQCR6 0x0148 102 | #define MCR_WTQCR7 0x014C 103 | #define MCR_WTQCR(x) (0x130 + 4 * (x)) 104 | #define TXQ_CNT_L GENMASK(15, 0) 105 | #define TXQ_CNT_H GENMASK(31, 16) 106 | 107 | #define MCR_SWPCDBGR 0x0154 108 | 109 | #define MCR_H2DSM2R 0x0160 /* supported in CONNAC2 */ 110 | #define MCR_H2DSM3R 0x0164 /* supported in CONNAC2 */ 111 | #define MCR_D2HRM3R 0x0174 /* supported in CONNAC2 */ 112 | #define MCR_WTQCR8 0x0190 /* supported in CONNAC2 */ 113 | #define MCR_WTQCR9 0x0194 /* supported in CONNAC2 */ 114 | #define MCR_WTQCR10 0x0198 /* supported in CONNAC2 */ 115 | #define MCR_WTQCR11 0x019C /* supported in CONNAC2 */ 116 | #define MCR_WTQCR12 0x01A0 /* supported in CONNAC2 */ 117 | #define MCR_WTQCR13 0x01A4 /* supported in CONNAC2 */ 118 | #define MCR_WTQCR14 0x01A8 /* supported in CONNAC2 */ 119 | #define MCR_WTQCR15 0x01AC /* supported in CONNAC2 */ 120 | 121 | enum mt76_connac_sdio_ver { 122 | MT76_CONNAC_SDIO, 123 | MT76_CONNAC2_SDIO, 124 | }; 125 | 126 | struct mt76s_intr { 127 | u32 isr; 128 | u32 *rec_mb; 129 | struct { 130 | u32 *wtqcr; 131 | } tx; 132 | struct { 133 | u16 *len[2]; 134 | u16 *num; 135 | } rx; 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | PROJECT(mt76-test C) 4 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3) 5 | 6 | ADD_EXECUTABLE(mt76-test main.c fields.c eeprom.c) 7 | TARGET_LINK_LIBRARIES(mt76-test nl-tiny) 8 | 9 | SET(CMAKE_INSTALL_PREFIX /usr) 10 | 11 | INSTALL(TARGETS mt76-test 12 | RUNTIME DESTINATION sbin 13 | ) 14 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # MT76 testmode utility 2 | 3 | This utility can be used to perform some support functions required for Rx/Tx calibration, similar to the ATE command set of the SDK driver. 4 | Its main functionality is setting test parameters and dumping statistics. It can also be used to prepare modified EEPROM data for writing into flash. 5 | 6 | ## Basic syntax 7 | 8 | - Set parameters: 9 | - `mt76-test phy0 set =`[...] 10 | - Show current parameter set: 11 | - `mt76-test phy0 dump` 12 | - Show statistics 13 | - `mt76-test phy0 dump stats` 14 | 15 | ## Running tests 16 | 17 | The test state is controlled through the `state` parameter. The following state values are supported: 18 | 19 | - `off`: Normal operation (default) 20 | - `idle`: Testmode enabled, but no specific test active 21 | - `tx_frames`: Send a number of packets with configurable rate/txpower 22 | - `rx_frames`: Receive packets and show RSSI and packet count/PER 23 | 24 | Setting a state activates it even if the value is the same as before. Setting it to `tx_frames` triggers sending packets immediately. Setting `rx_frames` enables receive mode and can also be used to clear rx statistics. 25 | 26 | ## Notes 27 | 28 | To run tests, you first need to disable all normal interfaces, set up a monitor mode interface and configure it to the channel/bandwidth you intend to use. 29 | 30 | 31 | ## Parameters: 32 | 33 | | Parameter name | ATE parameter | Description | 34 | |--|--|--| 35 | | `state` | `ATE` | Test state | 36 | | `tx_count` | `ATETXCNT` | Number of packets to send | 37 | | `tx_length` | `ATETXLEN` | Length of packets to send | 38 | | `tx_rate_mode` | `ATETXMODE` | PHY mode (possible values: `cck`, `ofdm`, `ht`, `vht`) | 39 | | `tx_rate_nss` | | Number of spatial streams (VHT only) | 40 | | `tx_rate_idx` | `ATETXMCS` | MCS or legacy rate index | 41 | | `tx_rate_sgi` | `ATETXGI` | Enable short guard interval | 42 | | `tx_rate_ldpc` | `ATETXLDPC` | Enable LDPC | 43 | | `tx_power_control` | `ATETXPOWERCTRL` | Firmware transmit power control feature | 44 | | `tx_power` | `ATETXPOW0-3` | Per-chain half-dBm transmit power, `0` means default value, e.g. `10,0,0,0` | 45 | | `tx_antenna` | `ATETXANT` | Transmit antenna bitmask | 46 | | `freq_offset` | `ATETXFREQOFFSET` | Frequency offset | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tools/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2020 Felix Fietkau */ 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include "mt76-test.h" 7 | 8 | struct unl unl; 9 | static uint32_t tm_changed[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)]; 10 | static const char *progname; 11 | 12 | static int phy_lookup_idx(const char *name) 13 | { 14 | char buf[128]; 15 | FILE *f; 16 | int len; 17 | 18 | snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 19 | f = fopen(buf, "r"); 20 | if (!f) 21 | return -1; 22 | 23 | len = fread(buf, 1, sizeof(buf) - 1, f); 24 | fclose(f); 25 | 26 | if (!len) 27 | return -1; 28 | 29 | buf[len] = 0; 30 | return atoi(buf); 31 | } 32 | 33 | void usage(void) 34 | { 35 | static const char *const commands[] = { 36 | "set = [...]", 37 | "dump [stats]", 38 | "eeprom file", 39 | "eeprom set = [...]", 40 | "eeprom changes", 41 | "eeprom reset", 42 | }; 43 | int i; 44 | 45 | fprintf(stderr, "Usage:\n"); 46 | for (i = 0; i < ARRAY_SIZE(commands); i++) 47 | printf(" %s phyX %s\n", progname, commands[i]); 48 | 49 | exit(1); 50 | } 51 | 52 | static int mt76_dump_cb(struct nl_msg *msg, void *arg) 53 | { 54 | struct nlattr *attr; 55 | 56 | attr = unl_find_attr(&unl, msg, NL80211_ATTR_TESTDATA); 57 | if (!attr) { 58 | fprintf(stderr, "Testdata attribute not found\n"); 59 | return NL_SKIP; 60 | } 61 | 62 | msg_field.print(&msg_field, attr); 63 | 64 | return NL_SKIP; 65 | } 66 | 67 | static int mt76_dump(int phy, int argc, char **argv) 68 | { 69 | struct nl_msg *msg; 70 | void *data; 71 | 72 | msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, true); 73 | nla_put_u32(msg, NL80211_ATTR_WIPHY, phy); 74 | 75 | data = nla_nest_start(msg, NL80211_ATTR_TESTDATA); 76 | 77 | for (; argc > 0; argc--, argv++) { 78 | if (!strcmp(argv[0], "stats")) 79 | nla_put_flag(msg, MT76_TM_ATTR_STATS); 80 | } 81 | 82 | nla_nest_end(msg, data); 83 | 84 | unl_genl_request(&unl, msg, mt76_dump_cb, NULL); 85 | 86 | return 0; 87 | } 88 | 89 | static inline void tm_set_changed(uint32_t id) 90 | { 91 | tm_changed[id / 32] |= (1U << (id % 32)); 92 | } 93 | 94 | static inline bool tm_is_changed(uint32_t id) 95 | { 96 | return tm_changed[id / 32] & (1U << (id % 32)); 97 | } 98 | 99 | static int mt76_set(int phy, int argc, char **argv) 100 | { 101 | const struct tm_field *fields = msg_field.fields; 102 | struct nl_msg *msg; 103 | void *data; 104 | int i, ret; 105 | 106 | if (argc < 1) 107 | return 1; 108 | 109 | msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, false); 110 | nla_put_u32(msg, NL80211_ATTR_WIPHY, phy); 111 | 112 | data = nla_nest_start(msg, NL80211_ATTR_TESTDATA); 113 | for (; argc > 0; argc--, argv++) { 114 | char *name = argv[0]; 115 | char *val = strchr(name, '='); 116 | 117 | if (!val) { 118 | fprintf(stderr, "Invalid argument: %s\n", name); 119 | return 1; 120 | } 121 | 122 | *(val++) = 0; 123 | 124 | for (i = 0; i < msg_field.len; i++) { 125 | if (!fields[i].parse) 126 | continue; 127 | 128 | if (!strcmp(fields[i].name, name)) 129 | break; 130 | } 131 | 132 | if (i == msg_field.len) { 133 | fprintf(stderr, "Unknown field: %s\n", name); 134 | return 1; 135 | } 136 | 137 | if (tm_is_changed(i)) { 138 | fprintf(stderr, "Duplicate field '%s'\n", name); 139 | return 1; 140 | } 141 | 142 | if (!fields[i].parse(&fields[i], i, msg, val)) 143 | return 1; 144 | 145 | tm_set_changed(i); 146 | } 147 | 148 | nla_nest_end(msg, data); 149 | 150 | ret = unl_genl_request(&unl, msg, NULL, NULL); 151 | if (ret) 152 | fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret)); 153 | 154 | return ret; 155 | } 156 | 157 | int main(int argc, char **argv) 158 | { 159 | const char *cmd; 160 | int phy; 161 | int ret = 0; 162 | 163 | progname = argv[0]; 164 | if (argc < 3) 165 | usage(); 166 | 167 | if (unl_genl_init(&unl, "nl80211") < 0) { 168 | fprintf(stderr, "Failed to connect to nl80211\n"); 169 | return 2; 170 | } 171 | 172 | phy = phy_lookup_idx(argv[1]); 173 | if (phy < 0) { 174 | fprintf(stderr, "Could not find phy '%s'\n", argv[1]); 175 | return 2; 176 | } 177 | 178 | cmd = argv[2]; 179 | argv += 3; 180 | argc -= 3; 181 | 182 | if (!strcmp(cmd, "dump")) 183 | ret = mt76_dump(phy, argc, argv); 184 | else if (!strcmp(cmd, "set")) 185 | ret = mt76_set(phy, argc, argv); 186 | else if (!strcmp(cmd, "eeprom")) 187 | ret = mt76_eeprom(phy, argc, argv); 188 | else 189 | usage(); 190 | 191 | unl_free(&unl); 192 | 193 | return ret; 194 | } 195 | -------------------------------------------------------------------------------- /tools/mt76-test.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* Copyright (C) 2020 Felix Fietkau */ 3 | #ifndef __MT76_TEST_H 4 | #define __MT76_TEST_H 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "../testmode.h" 13 | 14 | #ifndef ARRAY_SIZE 15 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 16 | #endif 17 | 18 | #ifndef DIV_ROUND_UP 19 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 20 | #endif 21 | 22 | #define EEPROM_FILE_PATH_FMT "/tmp/mt76-test-%s" 23 | #define EEPROM_PART_SIZE 20480 24 | 25 | struct nl_msg; 26 | struct nlattr; 27 | 28 | struct tm_field { 29 | const char *name; 30 | const char *prefix; 31 | 32 | bool (*parse)(const struct tm_field *field, int idx, struct nl_msg *msg, 33 | const char *val); 34 | void (*print)(const struct tm_field *field, struct nlattr *attr); 35 | 36 | union { 37 | struct { 38 | const char * const *enum_str; 39 | int enum_len; 40 | }; 41 | struct { 42 | bool (*parse2)(const struct tm_field *field, int idx, 43 | struct nl_msg *msg, const char *val); 44 | void (*print2)(const struct tm_field *field, 45 | struct nlattr *attr); 46 | }; 47 | struct { 48 | void (*print_extra)(const struct tm_field *field, 49 | struct nlattr **tb); 50 | const struct tm_field *fields; 51 | struct nla_policy *policy; 52 | int len; 53 | }; 54 | }; 55 | }; 56 | 57 | extern struct unl unl; 58 | extern const struct tm_field msg_field; 59 | extern unsigned char *eeprom_data; 60 | 61 | void usage(void); 62 | int mt76_eeprom(int phy, int argc, char **argv); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /trace.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | 8 | #ifndef __CHECKER__ 9 | #define CREATE_TRACE_POINTS 10 | #include "trace.h" 11 | 12 | EXPORT_TRACEPOINT_SYMBOL_GPL(mac_txdone); 13 | EXPORT_TRACEPOINT_SYMBOL_GPL(dev_irq); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /trace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #if !defined(__MT76_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 7 | #define __MT76_TRACE_H 8 | 9 | #include 10 | #include "mt76.h" 11 | 12 | #undef TRACE_SYSTEM 13 | #define TRACE_SYSTEM mt76 14 | 15 | #define MAXNAME 32 16 | #define DEV_ENTRY __array(char, wiphy_name, 32) 17 | #define DEVICE_ASSIGN strlcpy(__entry->wiphy_name, \ 18 | wiphy_name(dev->hw->wiphy), MAXNAME) 19 | #define DEV_PR_FMT "%s" 20 | #define DEV_PR_ARG __entry->wiphy_name 21 | 22 | #define REG_ENTRY __field(u32, reg) __field(u32, val) 23 | #define REG_ASSIGN __entry->reg = reg; __entry->val = val 24 | #define REG_PR_FMT " %04x=%08x" 25 | #define REG_PR_ARG __entry->reg, __entry->val 26 | 27 | #define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) 28 | #define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid 29 | #define TXID_PR_FMT " [%d:%d]" 30 | #define TXID_PR_ARG __entry->wcid, __entry->pktid 31 | 32 | DECLARE_EVENT_CLASS(dev_reg_evt, 33 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 34 | TP_ARGS(dev, reg, val), 35 | TP_STRUCT__entry( 36 | DEV_ENTRY 37 | REG_ENTRY 38 | ), 39 | TP_fast_assign( 40 | DEVICE_ASSIGN; 41 | REG_ASSIGN; 42 | ), 43 | TP_printk( 44 | DEV_PR_FMT REG_PR_FMT, 45 | DEV_PR_ARG, REG_PR_ARG 46 | ) 47 | ); 48 | 49 | DEFINE_EVENT(dev_reg_evt, reg_rr, 50 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 51 | TP_ARGS(dev, reg, val) 52 | ); 53 | 54 | DEFINE_EVENT(dev_reg_evt, reg_wr, 55 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 56 | TP_ARGS(dev, reg, val) 57 | ); 58 | 59 | TRACE_EVENT(dev_irq, 60 | TP_PROTO(struct mt76_dev *dev, u32 val, u32 mask), 61 | 62 | TP_ARGS(dev, val, mask), 63 | 64 | TP_STRUCT__entry( 65 | DEV_ENTRY 66 | __field(u32, val) 67 | __field(u32, mask) 68 | ), 69 | 70 | TP_fast_assign( 71 | DEVICE_ASSIGN; 72 | __entry->val = val; 73 | __entry->mask = mask; 74 | ), 75 | 76 | TP_printk( 77 | DEV_PR_FMT " %08x & %08x", 78 | DEV_PR_ARG, __entry->val, __entry->mask 79 | ) 80 | ); 81 | 82 | DECLARE_EVENT_CLASS(dev_txid_evt, 83 | TP_PROTO(struct mt76_dev *dev, u8 wcid, u8 pktid), 84 | TP_ARGS(dev, wcid, pktid), 85 | TP_STRUCT__entry( 86 | DEV_ENTRY 87 | TXID_ENTRY 88 | ), 89 | TP_fast_assign( 90 | DEVICE_ASSIGN; 91 | TXID_ASSIGN; 92 | ), 93 | TP_printk( 94 | DEV_PR_FMT TXID_PR_FMT, 95 | DEV_PR_ARG, TXID_PR_ARG 96 | ) 97 | ); 98 | 99 | DEFINE_EVENT(dev_txid_evt, mac_txdone, 100 | TP_PROTO(struct mt76_dev *dev, u8 wcid, u8 pktid), 101 | TP_ARGS(dev, wcid, pktid) 102 | ); 103 | 104 | #endif 105 | 106 | #undef TRACE_INCLUDE_PATH 107 | #define TRACE_INCLUDE_PATH . 108 | #undef TRACE_INCLUDE_FILE 109 | #define TRACE_INCLUDE_FILE trace 110 | 111 | #include 112 | -------------------------------------------------------------------------------- /usb_trace.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #include 7 | 8 | #ifndef __CHECKER__ 9 | #define CREATE_TRACE_POINTS 10 | #include "usb_trace.h" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /usb_trace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /* 3 | * Copyright (C) 2018 Lorenzo Bianconi 4 | */ 5 | 6 | #if !defined(__MT76_USB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 7 | #define __MT76_USB_TRACE_H 8 | 9 | #include 10 | #include "mt76.h" 11 | 12 | #undef TRACE_SYSTEM 13 | #define TRACE_SYSTEM mt76_usb 14 | 15 | #define MAXNAME 32 16 | #define DEV_ENTRY __array(char, wiphy_name, 32) 17 | #define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ 18 | wiphy_name(dev->hw->wiphy), MAXNAME) 19 | #define DEV_PR_FMT "%s " 20 | #define DEV_PR_ARG __entry->wiphy_name 21 | 22 | #define REG_ENTRY __field(u32, reg) __field(u32, val) 23 | #define REG_ASSIGN __entry->reg = reg; __entry->val = val 24 | #define REG_PR_FMT "reg:0x%04x=0x%08x" 25 | #define REG_PR_ARG __entry->reg, __entry->val 26 | 27 | DECLARE_EVENT_CLASS(dev_reg_evt, 28 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 29 | TP_ARGS(dev, reg, val), 30 | TP_STRUCT__entry( 31 | DEV_ENTRY 32 | REG_ENTRY 33 | ), 34 | TP_fast_assign( 35 | DEV_ASSIGN; 36 | REG_ASSIGN; 37 | ), 38 | TP_printk( 39 | DEV_PR_FMT REG_PR_FMT, 40 | DEV_PR_ARG, REG_PR_ARG 41 | ) 42 | ); 43 | 44 | DEFINE_EVENT(dev_reg_evt, usb_reg_rr, 45 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 46 | TP_ARGS(dev, reg, val) 47 | ); 48 | 49 | DEFINE_EVENT(dev_reg_evt, usb_reg_wr, 50 | TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), 51 | TP_ARGS(dev, reg, val) 52 | ); 53 | 54 | DECLARE_EVENT_CLASS(urb_transfer, 55 | TP_PROTO(struct mt76_dev *dev, struct urb *u), 56 | TP_ARGS(dev, u), 57 | TP_STRUCT__entry( 58 | DEV_ENTRY __field(unsigned int, pipe) __field(u32, len) 59 | ), 60 | TP_fast_assign( 61 | DEV_ASSIGN; 62 | __entry->pipe = u->pipe; 63 | __entry->len = u->transfer_buffer_length; 64 | ), 65 | TP_printk(DEV_PR_FMT "p:%08x len:%u", 66 | DEV_PR_ARG, __entry->pipe, __entry->len) 67 | ); 68 | 69 | DEFINE_EVENT(urb_transfer, submit_urb, 70 | TP_PROTO(struct mt76_dev *dev, struct urb *u), 71 | TP_ARGS(dev, u) 72 | ); 73 | 74 | DEFINE_EVENT(urb_transfer, rx_urb, 75 | TP_PROTO(struct mt76_dev *dev, struct urb *u), 76 | TP_ARGS(dev, u) 77 | ); 78 | 79 | #endif 80 | 81 | #undef TRACE_INCLUDE_PATH 82 | #define TRACE_INCLUDE_PATH . 83 | #undef TRACE_INCLUDE_FILE 84 | #define TRACE_INCLUDE_FILE usb_trace 85 | 86 | #include 87 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: ISC 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | */ 5 | 6 | #include 7 | #include "mt76.h" 8 | 9 | bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, 10 | int timeout) 11 | { 12 | u32 cur; 13 | 14 | timeout /= 10; 15 | do { 16 | cur = __mt76_rr(dev, offset) & mask; 17 | if (cur == val) 18 | return true; 19 | 20 | udelay(10); 21 | } while (timeout-- > 0); 22 | 23 | return false; 24 | } 25 | EXPORT_SYMBOL_GPL(__mt76_poll); 26 | 27 | bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, 28 | int timeout) 29 | { 30 | u32 cur; 31 | 32 | timeout /= 10; 33 | do { 34 | cur = __mt76_rr(dev, offset) & mask; 35 | if (cur == val) 36 | return true; 37 | 38 | usleep_range(10000, 20000); 39 | } while (timeout-- > 0); 40 | 41 | return false; 42 | } 43 | EXPORT_SYMBOL_GPL(__mt76_poll_msec); 44 | 45 | int mt76_wcid_alloc(u32 *mask, int size) 46 | { 47 | int i, idx = 0, cur; 48 | 49 | for (i = 0; i < DIV_ROUND_UP(size, 32); i++) { 50 | idx = ffs(~mask[i]); 51 | if (!idx) 52 | continue; 53 | 54 | idx--; 55 | cur = i * 32 + idx; 56 | if (cur >= size) 57 | break; 58 | 59 | mask[i] |= BIT(idx); 60 | return cur; 61 | } 62 | 63 | return -1; 64 | } 65 | EXPORT_SYMBOL_GPL(mt76_wcid_alloc); 66 | 67 | int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy) 68 | { 69 | struct mt76_wcid *wcid; 70 | int i, j, min_rssi = 0; 71 | s8 cur_rssi; 72 | 73 | local_bh_disable(); 74 | rcu_read_lock(); 75 | 76 | for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { 77 | u32 mask = dev->wcid_mask[i]; 78 | u32 phy_mask = dev->wcid_phy_mask[i]; 79 | 80 | if (!mask) 81 | continue; 82 | 83 | for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) { 84 | if (!(mask & 1)) 85 | continue; 86 | 87 | if (!!(phy_mask & 1) != ext_phy) 88 | continue; 89 | 90 | wcid = rcu_dereference(dev->wcid[j]); 91 | if (!wcid) 92 | continue; 93 | 94 | spin_lock(&dev->rx_lock); 95 | if (wcid->inactive_count++ < 5) 96 | cur_rssi = -ewma_signal_read(&wcid->rssi); 97 | else 98 | cur_rssi = 0; 99 | spin_unlock(&dev->rx_lock); 100 | 101 | if (cur_rssi < min_rssi) 102 | min_rssi = cur_rssi; 103 | } 104 | } 105 | 106 | rcu_read_unlock(); 107 | local_bh_enable(); 108 | 109 | return min_rssi; 110 | } 111 | EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi); 112 | 113 | int __mt76_worker_fn(void *ptr) 114 | { 115 | struct mt76_worker *w = ptr; 116 | 117 | while (!kthread_should_stop()) { 118 | set_current_state(TASK_INTERRUPTIBLE); 119 | 120 | if (kthread_should_park()) { 121 | kthread_parkme(); 122 | continue; 123 | } 124 | 125 | if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) { 126 | schedule(); 127 | continue; 128 | } 129 | 130 | set_bit(MT76_WORKER_RUNNING, &w->state); 131 | set_current_state(TASK_RUNNING); 132 | w->fn(w); 133 | cond_resched(); 134 | clear_bit(MT76_WORKER_RUNNING, &w->state); 135 | } 136 | 137 | return 0; 138 | } 139 | EXPORT_SYMBOL_GPL(__mt76_worker_fn); 140 | 141 | MODULE_LICENSE("Dual BSD/GPL"); 142 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2016 Felix Fietkau 4 | * Copyright (C) 2004 - 2009 Ivo van Doorn 5 | */ 6 | 7 | #ifndef __MT76_UTIL_H 8 | #define __MT76_UTIL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct mt76_worker 16 | { 17 | struct task_struct *task; 18 | void (*fn)(struct mt76_worker *); 19 | unsigned long state; 20 | }; 21 | 22 | enum { 23 | MT76_WORKER_SCHEDULED, 24 | MT76_WORKER_RUNNING, 25 | }; 26 | 27 | #define MT76_INCR(_var, _size) \ 28 | (_var = (((_var) + 1) % (_size))) 29 | 30 | int mt76_wcid_alloc(u32 *mask, int size); 31 | 32 | static inline bool 33 | mt76_wcid_mask_test(u32 *mask, int idx) 34 | { 35 | return mask[idx / 32] & BIT(idx % 32); 36 | } 37 | 38 | static inline void 39 | mt76_wcid_mask_set(u32 *mask, int idx) 40 | { 41 | mask[idx / 32] |= BIT(idx % 32); 42 | } 43 | 44 | static inline void 45 | mt76_wcid_mask_clear(u32 *mask, int idx) 46 | { 47 | mask[idx / 32] &= ~BIT(idx % 32); 48 | } 49 | 50 | static inline void 51 | mt76_skb_set_moredata(struct sk_buff *skb, bool enable) 52 | { 53 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 54 | 55 | if (enable) 56 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); 57 | else 58 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); 59 | } 60 | 61 | int __mt76_worker_fn(void *ptr); 62 | 63 | static inline int 64 | mt76_worker_setup(struct ieee80211_hw *hw, struct mt76_worker *w, 65 | void (*fn)(struct mt76_worker *), 66 | const char *name) 67 | { 68 | const char *dev_name = wiphy_name(hw->wiphy); 69 | int ret; 70 | 71 | if (fn) 72 | w->fn = fn; 73 | w->task = kthread_run(__mt76_worker_fn, w, 74 | "mt76-%s %s", name, dev_name); 75 | 76 | if (IS_ERR(w->task)) { 77 | ret = PTR_ERR(w->task); 78 | w->task = NULL; 79 | return ret; 80 | } 81 | 82 | return 0; 83 | } 84 | 85 | static inline void mt76_worker_schedule(struct mt76_worker *w) 86 | { 87 | if (!w->task) 88 | return; 89 | 90 | if (!test_and_set_bit(MT76_WORKER_SCHEDULED, &w->state) && 91 | !test_bit(MT76_WORKER_RUNNING, &w->state)) 92 | wake_up_process(w->task); 93 | } 94 | 95 | static inline void mt76_worker_disable(struct mt76_worker *w) 96 | { 97 | if (!w->task) 98 | return; 99 | 100 | kthread_park(w->task); 101 | WRITE_ONCE(w->state, 0); 102 | } 103 | 104 | static inline void mt76_worker_enable(struct mt76_worker *w) 105 | { 106 | if (!w->task) 107 | return; 108 | 109 | kthread_unpark(w->task); 110 | mt76_worker_schedule(w); 111 | } 112 | 113 | static inline void mt76_worker_teardown(struct mt76_worker *w) 114 | { 115 | if (!w->task) 116 | return; 117 | 118 | kthread_stop(w->task); 119 | w->task = NULL; 120 | } 121 | 122 | #endif 123 | --------------------------------------------------------------------------------