18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (c) Copyright 2002-2010, Ralink Technology, Inc. 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 68c2ecf20Sopenharmony_ci * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "mt76x0.h" 108c2ecf20Sopenharmony_ci#include "eeprom.h" 118c2ecf20Sopenharmony_ci#include "mcu.h" 128c2ecf20Sopenharmony_ci#include "initvals.h" 138c2ecf20Sopenharmony_ci#include "initvals_init.h" 148c2ecf20Sopenharmony_ci#include "../mt76x02_phy.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic void 178c2ecf20Sopenharmony_cimt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* Note: we don't turn off WLAN_CLK because that makes the device 228c2ecf20Sopenharmony_ci * not respond properly on the probe path. 238c2ecf20Sopenharmony_ci * In case anyone (PSM?) wants to use this function we can 248c2ecf20Sopenharmony_ci * bring the clock stuff back and fixup the probe path. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (enable) 288c2ecf20Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_EN | 298c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 308c2ecf20Sopenharmony_ci else 318c2ecf20Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 348c2ecf20Sopenharmony_ci udelay(20); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Note: vendor driver tries to disable/enable wlan here and retry 378c2ecf20Sopenharmony_ci * but the code which does it is so buggy it must have never 388c2ecf20Sopenharmony_ci * triggered, so don't bother. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000)) 418c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "PLL and XTAL check failed\n"); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_civoid mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci u32 val; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_WLAN_FUN_CTRL); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (reset) { 518c2ecf20Sopenharmony_ci val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; 528c2ecf20Sopenharmony_ci val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { 558c2ecf20Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | 568c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 578c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 588c2ecf20Sopenharmony_ci udelay(20); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | 618c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 668c2ecf20Sopenharmony_ci udelay(20); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci mt76x0_set_wlan_state(dev, val, enable); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x0_chip_onoff); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_SYS_CTRL, 758c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_CSR | 768c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_BBP); 778c2ecf20Sopenharmony_ci msleep(200); 788c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, 798c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_CSR | 808c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_BBP); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define RANDOM_WRITE(dev, tab) \ 848c2ecf20Sopenharmony_ci mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ 858c2ecf20Sopenharmony_ci tab, ARRAY_SIZE(tab)) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int mt76x0_init_bbp(struct mt76x02_dev *dev) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int ret, i; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = mt76x0_phy_wait_bbp_ready(dev); 928c2ecf20Sopenharmony_ci if (ret) 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci RANDOM_WRITE(dev, mt76x0_bbp_init_tab); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) { 988c2ecf20Sopenharmony_ci const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i]; 998c2ecf20Sopenharmony_ci const struct mt76_reg_pair *pair = &item->reg_pair; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20)) 1028c2ecf20Sopenharmony_ci mt76_wr(dev, pair->reg, pair->value); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci RANDOM_WRITE(dev, mt76x0_dcoc_tab); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void mt76x0_init_mac_registers(struct mt76x02_dev *dev) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci RANDOM_WRITE(dev, common_mac_reg_table); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ 1158c2ecf20Sopenharmony_ci RANDOM_WRITE(dev, mt76x0_mac_reg_table); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */ 1188c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, 0x3); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Set 0x141C[15:12]=0xF */ 1218c2ecf20Sopenharmony_ci mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * tx_ring 9 is for mgmt frame 1278c2ecf20Sopenharmony_ci * tx_ring 8 is for in-band command frame. 1288c2ecf20Sopenharmony_ci * WMM_RG0_TXQMA: this register setting is for FCE to 1298c2ecf20Sopenharmony_ci * define the rule of tx_ring 9 1308c2ecf20Sopenharmony_ci * WMM_RG1_TXQMA: this register setting is for FCE to 1318c2ecf20Sopenharmony_ci * define the rule of tx_ring 8 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_civoid mt76x0_mac_stop(struct mt76x02_dev *dev) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int i = 200, ok = 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Page count on TxQ */ 1438c2ecf20Sopenharmony_ci while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || 1448c2ecf20Sopenharmony_ci (mt76_rr(dev, 0x0a30) & 0x000000ff) || 1458c2ecf20Sopenharmony_ci (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) 1468c2ecf20Sopenharmony_ci msleep(10); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) 1498c2ecf20Sopenharmony_ci dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n"); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | 1528c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Page count on RxQ */ 1558c2ecf20Sopenharmony_ci for (i = 0; i < 200; i++) { 1568c2ecf20Sopenharmony_ci if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && 1578c2ecf20Sopenharmony_ci !mt76_rr(dev, 0x0a30) && 1588c2ecf20Sopenharmony_ci !mt76_rr(dev, 0x0a34)) { 1598c2ecf20Sopenharmony_ci if (ok++ > 5) 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci continue; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci msleep(1); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) 1678c2ecf20Sopenharmony_ci dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n"); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x0_mac_stop); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint mt76x0_init_hardware(struct mt76x02_dev *dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int ret, i, k; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000)) 1768c2ecf20Sopenharmony_ci return -EIO; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Wait for ASIC ready after FW load. */ 1798c2ecf20Sopenharmony_ci if (!mt76x02_wait_for_mac(&dev->mt76)) 1808c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mt76x0_reset_csr_bbp(dev); 1838c2ecf20Sopenharmony_ci ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1); 1848c2ecf20Sopenharmony_ci if (ret) 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci mt76x0_init_mac_registers(dev); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) 1908c2ecf20Sopenharmony_ci return -EIO; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ret = mt76x0_init_bbp(dev); 1938c2ecf20Sopenharmony_ci if (ret) 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 1998c2ecf20Sopenharmony_ci for (k = 0; k < 4; k++) 2008c2ecf20Sopenharmony_ci mt76x02_mac_shared_key_setup(dev, i, k, NULL); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) 2038c2ecf20Sopenharmony_ci mt76x02_mac_wcid_setup(dev, i, 0, NULL); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ret = mt76x0_eeprom_init(dev); 2068c2ecf20Sopenharmony_ci if (ret) 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mt76x0_phy_init(dev); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x0_init_hardware); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void 2168c2ecf20Sopenharmony_cimt76x0_init_txpower(struct mt76x02_dev *dev, 2178c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 2208c2ecf20Sopenharmony_ci struct mt76_rate_power t; 2218c2ecf20Sopenharmony_ci s8 tp; 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 2258c2ecf20Sopenharmony_ci chan = &sband->channels[i]; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci mt76x0_get_tx_power_per_rate(dev, chan, &t); 2288c2ecf20Sopenharmony_ci mt76x0_get_power_info(dev, chan, &tp); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci chan->orig_mpwr = (mt76x02_get_max_rate_power(&t) + tp) / 2; 2318c2ecf20Sopenharmony_ci chan->max_power = min_t(int, chan->max_reg_power, 2328c2ecf20Sopenharmony_ci chan->orig_mpwr); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ciint mt76x0_register_device(struct mt76x02_dev *dev) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci int ret; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci mt76x02_init_device(dev); 2418c2ecf20Sopenharmony_ci mt76x02_config_mac_addr_list(dev); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, 2448c2ecf20Sopenharmony_ci ARRAY_SIZE(mt76x02_rates)); 2458c2ecf20Sopenharmony_ci if (ret) 2468c2ecf20Sopenharmony_ci return ret; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (dev->mphy.cap.has_5ghz) { 2498c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci sband = &dev->mphy.sband_5g.sband; 2528c2ecf20Sopenharmony_ci sband->vht_cap.cap &= ~IEEE80211_VHT_CAP_RXLDPC; 2538c2ecf20Sopenharmony_ci mt76x0_init_txpower(dev, sband); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (dev->mphy.cap.has_2ghz) 2578c2ecf20Sopenharmony_ci mt76x0_init_txpower(dev, &dev->mphy.sband_2g.sband); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mt76x02_init_debugfs(dev); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x0_register_device); 264