162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (c) Copyright 2002-2010, Ralink Technology, Inc. 462306a36Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 562306a36Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "mt7601u.h" 962306a36Sopenharmony_ci#include "eeprom.h" 1062306a36Sopenharmony_ci#include "trace.h" 1162306a36Sopenharmony_ci#include "mcu.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "initvals.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic void 1662306a36Sopenharmony_cimt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci int i; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* Note: we don't turn off WLAN_CLK because that makes the device 2162306a36Sopenharmony_ci * not respond properly on the probe path. 2262306a36Sopenharmony_ci * In case anyone (PSM?) wants to use this function we can 2362306a36Sopenharmony_ci * bring the clock stuff back and fixup the probe path. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (enable) 2762306a36Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_EN | 2862306a36Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 2962306a36Sopenharmony_ci else 3062306a36Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 3362306a36Sopenharmony_ci udelay(20); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (enable) { 3662306a36Sopenharmony_ci set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); 3762306a36Sopenharmony_ci } else { 3862306a36Sopenharmony_ci clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); 3962306a36Sopenharmony_ci return; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci for (i = 200; i; i--) { 4362306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_CMB_CTRL); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) 4662306a36Sopenharmony_ci break; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci udelay(20); 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* Note: vendor driver tries to disable/enable wlan here and retry 5262306a36Sopenharmony_ci * but the code which does it is so buggy it must have never 5362306a36Sopenharmony_ci * triggered, so don't bother. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci if (!i) 5662306a36Sopenharmony_ci dev_err(dev->dev, "Error: PLL and XTAL check failed!\n"); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci u32 val; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci mutex_lock(&dev->hw_atomic_mutex); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (reset) { 6862306a36Sopenharmony_ci val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; 6962306a36Sopenharmony_ci val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { 7262306a36Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | 7362306a36Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 7462306a36Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 7562306a36Sopenharmony_ci udelay(20); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | 7862306a36Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 8362306a36Sopenharmony_ci udelay(20); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mt7601u_set_wlan_state(dev, val, enable); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci mutex_unlock(&dev->hw_atomic_mutex); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR | 9362306a36Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_BBP)); 9462306a36Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, 0); 9562306a36Sopenharmony_ci msleep(1); 9662306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void mt7601u_init_usb_dma(struct mt7601u_dev *dev) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci u32 val; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci val = FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) | 10462306a36Sopenharmony_ci FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, 10562306a36Sopenharmony_ci MT_USB_AGGR_SIZE_LIMIT) | 10662306a36Sopenharmony_ci MT_USB_DMA_CFG_RX_BULK_EN | 10762306a36Sopenharmony_ci MT_USB_DMA_CFG_TX_BULK_EN; 10862306a36Sopenharmony_ci if (dev->in_max_packet == 512) 10962306a36Sopenharmony_ci val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; 11062306a36Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP; 11362306a36Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 11462306a36Sopenharmony_ci val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP; 11562306a36Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int mt7601u_init_bbp(struct mt7601u_dev *dev) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci int ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = mt7601u_wait_bbp_ready(dev); 12362306a36Sopenharmony_ci if (ret) 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals, 12762306a36Sopenharmony_ci ARRAY_SIZE(bbp_common_vals)); 12862306a36Sopenharmony_ci if (ret) 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals, 13262306a36Sopenharmony_ci ARRAY_SIZE(bbp_chip_vals)); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void 13662306a36Sopenharmony_cimt76_init_beacon_offsets(struct mt7601u_dev *dev) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci u16 base = MT_BEACON_BASE; 13962306a36Sopenharmony_ci u32 regs[4] = {}; 14062306a36Sopenharmony_ci int i; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 14362306a36Sopenharmony_ci u16 addr = dev->beacon_offsets[i]; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci for (i = 0; i < 4; i++) 14962306a36Sopenharmony_ci mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int mt7601u_write_mac_initvals(struct mt7601u_dev *dev) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci int ret; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals, 15762306a36Sopenharmony_ci ARRAY_SIZE(mac_common_vals)); 15862306a36Sopenharmony_ci if (ret) 15962306a36Sopenharmony_ci return ret; 16062306a36Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, 16162306a36Sopenharmony_ci mac_chip_vals, ARRAY_SIZE(mac_chip_vals)); 16262306a36Sopenharmony_ci if (ret) 16362306a36Sopenharmony_ci return ret; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci mt76_init_beacon_offsets(dev); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mt7601u_wr(dev, MT_AUX_CLK_CFG, 0); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int mt7601u_init_wcid_mem(struct mt7601u_dev *dev) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci u32 *vals; 17562306a36Sopenharmony_ci int i, ret; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); 17862306a36Sopenharmony_ci if (!vals) 17962306a36Sopenharmony_ci return -ENOMEM; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (i = 0; i < N_WCIDS; i++) { 18262306a36Sopenharmony_ci vals[i * 2] = 0xffffffff; 18362306a36Sopenharmony_ci vals[i * 2 + 1] = 0x00ffffff; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE, 18762306a36Sopenharmony_ci vals, N_WCIDS * 2); 18862306a36Sopenharmony_ci kfree(vals); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int mt7601u_init_key_mem(struct mt7601u_dev *dev) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci u32 vals[4] = {}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0, 19862306a36Sopenharmony_ci vals, ARRAY_SIZE(vals)); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci u32 *vals; 20462306a36Sopenharmony_ci int i, ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); 20762306a36Sopenharmony_ci if (!vals) 20862306a36Sopenharmony_ci return -ENOMEM; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci for (i = 0; i < N_WCIDS * 2; i++) 21162306a36Sopenharmony_ci vals[i] = 1; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE, 21462306a36Sopenharmony_ci vals, N_WCIDS * 2); 21562306a36Sopenharmony_ci kfree(vals); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void mt7601u_reset_counters(struct mt7601u_dev *dev) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT0); 22362306a36Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT1); 22462306a36Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT2); 22562306a36Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT0); 22662306a36Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT1); 22762306a36Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT2); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint mt7601u_mac_start(struct mt7601u_dev *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 23562306a36Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) 23662306a36Sopenharmony_ci return -ETIMEDOUT; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR | 23962306a36Sopenharmony_ci MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | 24062306a36Sopenharmony_ci MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | 24162306a36Sopenharmony_ci MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | 24262306a36Sopenharmony_ci MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | 24362306a36Sopenharmony_ci MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | 24462306a36Sopenharmony_ci MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; 24562306a36Sopenharmony_ci mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 24862306a36Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 25162306a36Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50)) 25262306a36Sopenharmony_ci return -ETIMEDOUT; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci int i, ok; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | 26562306a36Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | 26662306a36Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) 26962306a36Sopenharmony_ci dev_warn(dev->dev, "Warning: TX DMA did not stop!\n"); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Page count on TxQ */ 27262306a36Sopenharmony_ci i = 200; 27362306a36Sopenharmony_ci while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || 27462306a36Sopenharmony_ci (mt76_rr(dev, 0x0a30) & 0x000000ff) || 27562306a36Sopenharmony_ci (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) 27662306a36Sopenharmony_ci msleep(10); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) 27962306a36Sopenharmony_ci dev_warn(dev->dev, "Warning: MAC TX did not stop!\n"); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | 28262306a36Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Page count on RxQ */ 28562306a36Sopenharmony_ci ok = 0; 28662306a36Sopenharmony_ci i = 200; 28762306a36Sopenharmony_ci while (i--) { 28862306a36Sopenharmony_ci if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && 28962306a36Sopenharmony_ci !mt76_rr(dev, 0x0a30) && 29062306a36Sopenharmony_ci !mt76_rr(dev, 0x0a34)) { 29162306a36Sopenharmony_ci if (ok++ > 5) 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci continue; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci msleep(1); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) 29962306a36Sopenharmony_ci dev_warn(dev->dev, "Warning: MAC RX did not stop!\n"); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) 30262306a36Sopenharmony_ci dev_warn(dev->dev, "Warning: RX DMA did not stop!\n"); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_civoid mt7601u_mac_stop(struct mt7601u_dev *dev) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci mt7601u_mac_stop_hw(dev); 30862306a36Sopenharmony_ci flush_delayed_work(&dev->stat_work); 30962306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->stat_work); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void mt7601u_stop_hardware(struct mt7601u_dev *dev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci mt7601u_chip_onoff(dev, false, false); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciint mt7601u_init_hardware(struct mt7601u_dev *dev) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci static const u16 beacon_offsets[16] = { 32062306a36Sopenharmony_ci /* 512 byte per beacon */ 32162306a36Sopenharmony_ci 0xc000, 0xc200, 0xc400, 0xc600, 32262306a36Sopenharmony_ci 0xc800, 0xca00, 0xcc00, 0xce00, 32362306a36Sopenharmony_ci 0xd000, 0xd200, 0xd400, 0xd600, 32462306a36Sopenharmony_ci 0xd800, 0xda00, 0xdc00, 0xde00 32562306a36Sopenharmony_ci }; 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci dev->beacon_offsets = beacon_offsets; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci mt7601u_chip_onoff(dev, true, false); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci ret = mt7601u_wait_asic_ready(dev); 33362306a36Sopenharmony_ci if (ret) 33462306a36Sopenharmony_ci goto err; 33562306a36Sopenharmony_ci ret = mt7601u_mcu_init(dev); 33662306a36Sopenharmony_ci if (ret) 33762306a36Sopenharmony_ci goto err; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, 34062306a36Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 34162306a36Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { 34262306a36Sopenharmony_ci ret = -EIO; 34362306a36Sopenharmony_ci goto err; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Wait for ASIC ready after FW load. */ 34762306a36Sopenharmony_ci ret = mt7601u_wait_asic_ready(dev); 34862306a36Sopenharmony_ci if (ret) 34962306a36Sopenharmony_ci goto err; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mt7601u_reset_csr_bbp(dev); 35262306a36Sopenharmony_ci mt7601u_init_usb_dma(dev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ret = mt7601u_mcu_cmd_init(dev); 35562306a36Sopenharmony_ci if (ret) 35662306a36Sopenharmony_ci goto err; 35762306a36Sopenharmony_ci ret = mt7601u_dma_init(dev); 35862306a36Sopenharmony_ci if (ret) 35962306a36Sopenharmony_ci goto err_mcu; 36062306a36Sopenharmony_ci ret = mt7601u_write_mac_initvals(dev); 36162306a36Sopenharmony_ci if (ret) 36262306a36Sopenharmony_ci goto err_rx; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!mt76_poll_msec(dev, MT_MAC_STATUS, 36562306a36Sopenharmony_ci MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) { 36662306a36Sopenharmony_ci ret = -EIO; 36762306a36Sopenharmony_ci goto err_rx; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = mt7601u_init_bbp(dev); 37162306a36Sopenharmony_ci if (ret) 37262306a36Sopenharmony_ci goto err_rx; 37362306a36Sopenharmony_ci ret = mt7601u_init_wcid_mem(dev); 37462306a36Sopenharmony_ci if (ret) 37562306a36Sopenharmony_ci goto err_rx; 37662306a36Sopenharmony_ci ret = mt7601u_init_key_mem(dev); 37762306a36Sopenharmony_ci if (ret) 37862306a36Sopenharmony_ci goto err_rx; 37962306a36Sopenharmony_ci ret = mt7601u_init_wcid_attr_mem(dev); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci goto err_rx; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | 38462306a36Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | 38562306a36Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN | 38662306a36Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX)); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci mt7601u_reset_counters(dev); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci mt7601u_wr(dev, MT_TXOP_CTRL_CFG, 39362306a36Sopenharmony_ci FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | 39462306a36Sopenharmony_ci FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ret = mt7601u_eeprom_init(dev); 39762306a36Sopenharmony_ci if (ret) 39862306a36Sopenharmony_ci goto err_rx; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ret = mt7601u_phy_init(dev); 40162306a36Sopenharmony_ci if (ret) 40262306a36Sopenharmony_ci goto err_rx; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mt7601u_set_rx_path(dev, 0); 40562306a36Sopenharmony_ci mt7601u_set_tx_dac(dev, 0); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci mt7601u_mac_set_ctrlch(dev, false); 40862306a36Sopenharmony_ci mt7601u_bbp_set_ctrlch(dev, false); 40962306a36Sopenharmony_ci mt7601u_bbp_set_bw(dev, MT_BW_20); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cierr_rx: 41462306a36Sopenharmony_ci mt7601u_dma_cleanup(dev); 41562306a36Sopenharmony_cierr_mcu: 41662306a36Sopenharmony_ci mt7601u_mcu_cmd_deinit(dev); 41762306a36Sopenharmony_cierr: 41862306a36Sopenharmony_ci mt7601u_chip_onoff(dev, false, false); 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_civoid mt7601u_cleanup(struct mt7601u_dev *dev) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state)) 42562306a36Sopenharmony_ci return; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci mt7601u_stop_hardware(dev); 42862306a36Sopenharmony_ci mt7601u_dma_cleanup(dev); 42962306a36Sopenharmony_ci mt7601u_mcu_cmd_deinit(dev); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistruct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct ieee80211_hw *hw; 43562306a36Sopenharmony_ci struct mt7601u_dev *dev; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops); 43862306a36Sopenharmony_ci if (!hw) 43962306a36Sopenharmony_ci return NULL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci dev = hw->priv; 44262306a36Sopenharmony_ci dev->dev = pdev; 44362306a36Sopenharmony_ci dev->hw = hw; 44462306a36Sopenharmony_ci mutex_init(&dev->vendor_req_mutex); 44562306a36Sopenharmony_ci mutex_init(&dev->reg_atomic_mutex); 44662306a36Sopenharmony_ci mutex_init(&dev->hw_atomic_mutex); 44762306a36Sopenharmony_ci mutex_init(&dev->mutex); 44862306a36Sopenharmony_ci spin_lock_init(&dev->tx_lock); 44962306a36Sopenharmony_ci spin_lock_init(&dev->rx_lock); 45062306a36Sopenharmony_ci spin_lock_init(&dev->lock); 45162306a36Sopenharmony_ci spin_lock_init(&dev->mac_lock); 45262306a36Sopenharmony_ci spin_lock_init(&dev->con_mon_lock); 45362306a36Sopenharmony_ci atomic_set(&dev->avg_ampdu_len, 1); 45462306a36Sopenharmony_ci skb_queue_head_init(&dev->tx_skb_done); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); 45762306a36Sopenharmony_ci if (!dev->stat_wq) { 45862306a36Sopenharmony_ci ieee80211_free_hw(hw); 45962306a36Sopenharmony_ci return NULL; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return dev; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci#define CHAN2G(_idx, _freq) { \ 46662306a36Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 46762306a36Sopenharmony_ci .center_freq = (_freq), \ 46862306a36Sopenharmony_ci .hw_value = (_idx), \ 46962306a36Sopenharmony_ci .max_power = 30, \ 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic const struct ieee80211_channel mt76_channels_2ghz[] = { 47362306a36Sopenharmony_ci CHAN2G(1, 2412), 47462306a36Sopenharmony_ci CHAN2G(2, 2417), 47562306a36Sopenharmony_ci CHAN2G(3, 2422), 47662306a36Sopenharmony_ci CHAN2G(4, 2427), 47762306a36Sopenharmony_ci CHAN2G(5, 2432), 47862306a36Sopenharmony_ci CHAN2G(6, 2437), 47962306a36Sopenharmony_ci CHAN2G(7, 2442), 48062306a36Sopenharmony_ci CHAN2G(8, 2447), 48162306a36Sopenharmony_ci CHAN2G(9, 2452), 48262306a36Sopenharmony_ci CHAN2G(10, 2457), 48362306a36Sopenharmony_ci CHAN2G(11, 2462), 48462306a36Sopenharmony_ci CHAN2G(12, 2467), 48562306a36Sopenharmony_ci CHAN2G(13, 2472), 48662306a36Sopenharmony_ci CHAN2G(14, 2484), 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define CCK_RATE(_idx, _rate) { \ 49062306a36Sopenharmony_ci .bitrate = _rate, \ 49162306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ 49262306a36Sopenharmony_ci .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ 49362306a36Sopenharmony_ci .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci#define OFDM_RATE(_idx, _rate) { \ 49762306a36Sopenharmony_ci .bitrate = _rate, \ 49862306a36Sopenharmony_ci .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ 49962306a36Sopenharmony_ci .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic struct ieee80211_rate mt76_rates[] = { 50362306a36Sopenharmony_ci CCK_RATE(0, 10), 50462306a36Sopenharmony_ci CCK_RATE(1, 20), 50562306a36Sopenharmony_ci CCK_RATE(2, 55), 50662306a36Sopenharmony_ci CCK_RATE(3, 110), 50762306a36Sopenharmony_ci OFDM_RATE(0, 60), 50862306a36Sopenharmony_ci OFDM_RATE(1, 90), 50962306a36Sopenharmony_ci OFDM_RATE(2, 120), 51062306a36Sopenharmony_ci OFDM_RATE(3, 180), 51162306a36Sopenharmony_ci OFDM_RATE(4, 240), 51262306a36Sopenharmony_ci OFDM_RATE(5, 360), 51362306a36Sopenharmony_ci OFDM_RATE(6, 480), 51462306a36Sopenharmony_ci OFDM_RATE(7, 540), 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic int 51862306a36Sopenharmony_cimt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband, 51962306a36Sopenharmony_ci const struct ieee80211_channel *chan, int n_chan, 52062306a36Sopenharmony_ci struct ieee80211_rate *rates, int n_rates) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap; 52362306a36Sopenharmony_ci void *chanlist; 52462306a36Sopenharmony_ci int size; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci size = n_chan * sizeof(*chan); 52762306a36Sopenharmony_ci chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 52862306a36Sopenharmony_ci if (!chanlist) 52962306a36Sopenharmony_ci return -ENOMEM; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci sband->channels = chanlist; 53262306a36Sopenharmony_ci sband->n_channels = n_chan; 53362306a36Sopenharmony_ci sband->bitrates = rates; 53462306a36Sopenharmony_ci sband->n_bitrates = n_rates; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci ht_cap = &sband->ht_cap; 53762306a36Sopenharmony_ci ht_cap->ht_supported = true; 53862306a36Sopenharmony_ci ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 53962306a36Sopenharmony_ci IEEE80211_HT_CAP_GRN_FLD | 54062306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 54162306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | 54262306a36Sopenharmony_ci (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ht_cap->mcs.rx_mask[0] = 0xff; 54562306a36Sopenharmony_ci ht_cap->mcs.rx_mask[4] = 0x1; 54662306a36Sopenharmony_ci ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 54762306a36Sopenharmony_ci ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 54862306a36Sopenharmony_ci ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci dev->chandef.chan = &sband->channels[0]; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int 55662306a36Sopenharmony_cimt76_init_sband_2g(struct mt7601u_dev *dev) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g), 55962306a36Sopenharmony_ci GFP_KERNEL); 56062306a36Sopenharmony_ci if (!dev->sband_2g) 56162306a36Sopenharmony_ci return -ENOMEM; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = dev->sband_2g; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > 56662306a36Sopenharmony_ci ARRAY_SIZE(mt76_channels_2ghz)); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return mt76_init_sband(dev, dev->sband_2g, 56962306a36Sopenharmony_ci &mt76_channels_2ghz[dev->ee->reg.start - 1], 57062306a36Sopenharmony_ci dev->ee->reg.num, 57162306a36Sopenharmony_ci mt76_rates, ARRAY_SIZE(mt76_rates)); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciint mt7601u_register_device(struct mt7601u_dev *dev) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct ieee80211_hw *hw = dev->hw; 57762306a36Sopenharmony_ci struct wiphy *wiphy = hw->wiphy; 57862306a36Sopenharmony_ci int ret; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to 58162306a36Sopenharmony_ci * entry no. 1 like it does in the vendor driver. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci dev->wcid_mask[0] |= 1; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* init fake wcid for monitor interfaces */ 58662306a36Sopenharmony_ci dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid), 58762306a36Sopenharmony_ci GFP_KERNEL); 58862306a36Sopenharmony_ci if (!dev->mon_wcid) 58962306a36Sopenharmony_ci return -ENOMEM; 59062306a36Sopenharmony_ci dev->mon_wcid->idx = 0xff; 59162306a36Sopenharmony_ci dev->mon_wcid->hw_key_idx = -1; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci SET_IEEE80211_DEV(hw, dev->dev); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci hw->queues = 4; 59662306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 59762306a36Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 59862306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 59962306a36Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 60062306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 60162306a36Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 60262306a36Sopenharmony_ci hw->max_rates = 1; 60362306a36Sopenharmony_ci hw->max_report_rates = 7; 60462306a36Sopenharmony_ci hw->max_rate_tries = 1; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci hw->sta_data_size = sizeof(struct mt76_sta); 60762306a36Sopenharmony_ci hw->vif_data_size = sizeof(struct mt76_vif); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 61262306a36Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 61362306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = mt76_init_sband_2g(dev); 61862306a36Sopenharmony_ci if (ret) 61962306a36Sopenharmony_ci return ret; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work); 62262306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci ret = ieee80211_register_hw(hw); 62562306a36Sopenharmony_ci if (ret) 62662306a36Sopenharmony_ci return ret; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci mt7601u_init_debugfs(dev); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 632