developer | 0f312e8 | 2022-11-01 12:31:52 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| 4 | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| 5 | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| 6 | * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> |
| 7 | */ |
| 8 | |
| 9 | #include "mt76x0.h" |
| 10 | #include "eeprom.h" |
| 11 | #include "mcu.h" |
| 12 | #include "initvals.h" |
| 13 | #include "initvals_init.h" |
| 14 | #include "../mt76x02_phy.h" |
| 15 | |
| 16 | static void |
| 17 | mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable) |
| 18 | { |
| 19 | u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD; |
| 20 | |
| 21 | /* Note: we don't turn off WLAN_CLK because that makes the device |
| 22 | * not respond properly on the probe path. |
| 23 | * In case anyone (PSM?) wants to use this function we can |
| 24 | * bring the clock stuff back and fixup the probe path. |
| 25 | */ |
| 26 | |
| 27 | if (enable) |
| 28 | val |= (MT_WLAN_FUN_CTRL_WLAN_EN | |
| 29 | MT_WLAN_FUN_CTRL_WLAN_CLK_EN); |
| 30 | else |
| 31 | val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); |
| 32 | |
| 33 | mt76_wr(dev, MT_WLAN_FUN_CTRL, val); |
| 34 | udelay(20); |
| 35 | |
| 36 | /* Note: vendor driver tries to disable/enable wlan here and retry |
| 37 | * but the code which does it is so buggy it must have never |
| 38 | * triggered, so don't bother. |
| 39 | */ |
| 40 | if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000)) |
| 41 | dev_err(dev->mt76.dev, "PLL and XTAL check failed\n"); |
| 42 | } |
| 43 | |
| 44 | void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset) |
| 45 | { |
| 46 | u32 val; |
| 47 | |
| 48 | val = mt76_rr(dev, MT_WLAN_FUN_CTRL); |
| 49 | |
| 50 | if (reset) { |
| 51 | val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; |
| 52 | val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; |
| 53 | |
| 54 | if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { |
| 55 | val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | |
| 56 | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); |
| 57 | mt76_wr(dev, MT_WLAN_FUN_CTRL, val); |
| 58 | udelay(20); |
| 59 | |
| 60 | val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | |
| 61 | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | mt76_wr(dev, MT_WLAN_FUN_CTRL, val); |
| 66 | udelay(20); |
| 67 | |
| 68 | mt76x0_set_wlan_state(dev, val, enable); |
| 69 | } |
| 70 | EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); |
| 71 | |
| 72 | static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev) |
| 73 | { |
| 74 | mt76_wr(dev, MT_MAC_SYS_CTRL, |
| 75 | MT_MAC_SYS_CTRL_RESET_CSR | |
| 76 | MT_MAC_SYS_CTRL_RESET_BBP); |
| 77 | msleep(200); |
| 78 | mt76_clear(dev, MT_MAC_SYS_CTRL, |
| 79 | MT_MAC_SYS_CTRL_RESET_CSR | |
| 80 | MT_MAC_SYS_CTRL_RESET_BBP); |
| 81 | } |
| 82 | |
| 83 | #define RANDOM_WRITE(dev, tab) \ |
| 84 | mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ |
| 85 | tab, ARRAY_SIZE(tab)) |
| 86 | |
| 87 | static int mt76x0_init_bbp(struct mt76x02_dev *dev) |
| 88 | { |
| 89 | int ret, i; |
| 90 | |
| 91 | ret = mt76x0_phy_wait_bbp_ready(dev); |
| 92 | if (ret) |
| 93 | return ret; |
| 94 | |
| 95 | RANDOM_WRITE(dev, mt76x0_bbp_init_tab); |
| 96 | |
| 97 | for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) { |
| 98 | const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i]; |
| 99 | const struct mt76_reg_pair *pair = &item->reg_pair; |
| 100 | |
| 101 | if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20)) |
| 102 | mt76_wr(dev, pair->reg, pair->value); |
| 103 | } |
| 104 | |
| 105 | RANDOM_WRITE(dev, mt76x0_dcoc_tab); |
| 106 | |
| 107 | return 0; |
| 108 | } |
| 109 | |
| 110 | static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) |
| 111 | { |
| 112 | RANDOM_WRITE(dev, common_mac_reg_table); |
| 113 | |
| 114 | /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ |
| 115 | RANDOM_WRITE(dev, mt76x0_mac_reg_table); |
| 116 | |
| 117 | /* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */ |
| 118 | mt76_clear(dev, MT_MAC_SYS_CTRL, 0x3); |
| 119 | |
| 120 | /* Set 0x141C[15:12]=0xF */ |
| 121 | mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); |
| 122 | |
| 123 | mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); |
| 124 | |
| 125 | /* |
| 126 | * tx_ring 9 is for mgmt frame |
| 127 | * tx_ring 8 is for in-band command frame. |
| 128 | * WMM_RG0_TXQMA: this register setting is for FCE to |
| 129 | * define the rule of tx_ring 9 |
| 130 | * WMM_RG1_TXQMA: this register setting is for FCE to |
| 131 | * define the rule of tx_ring 8 |
| 132 | */ |
| 133 | mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); |
| 134 | } |
| 135 | |
| 136 | void mt76x0_mac_stop(struct mt76x02_dev *dev) |
| 137 | { |
| 138 | int i = 200, ok = 0; |
| 139 | |
| 140 | mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); |
| 141 | |
| 142 | /* Page count on TxQ */ |
| 143 | while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || |
| 144 | (mt76_rr(dev, 0x0a30) & 0x000000ff) || |
| 145 | (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) |
| 146 | msleep(10); |
| 147 | |
| 148 | if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) |
| 149 | dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n"); |
| 150 | |
| 151 | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | |
| 152 | MT_MAC_SYS_CTRL_ENABLE_TX); |
| 153 | |
| 154 | /* Page count on RxQ */ |
| 155 | for (i = 0; i < 200; i++) { |
| 156 | if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && |
| 157 | !mt76_rr(dev, 0x0a30) && |
| 158 | !mt76_rr(dev, 0x0a34)) { |
| 159 | if (ok++ > 5) |
| 160 | break; |
| 161 | continue; |
| 162 | } |
| 163 | msleep(1); |
| 164 | } |
| 165 | |
| 166 | if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) |
| 167 | dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n"); |
| 168 | } |
| 169 | EXPORT_SYMBOL_GPL(mt76x0_mac_stop); |
| 170 | |
| 171 | int mt76x0_init_hardware(struct mt76x02_dev *dev) |
| 172 | { |
| 173 | int ret, i, k; |
| 174 | |
| 175 | if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000)) |
| 176 | return -EIO; |
| 177 | |
| 178 | /* Wait for ASIC ready after FW load. */ |
| 179 | if (!mt76x02_wait_for_mac(&dev->mt76)) |
| 180 | return -ETIMEDOUT; |
| 181 | |
| 182 | mt76x0_reset_csr_bbp(dev); |
| 183 | ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1); |
| 184 | if (ret) |
| 185 | return ret; |
| 186 | |
| 187 | mt76x0_init_mac_registers(dev); |
| 188 | |
| 189 | if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) |
| 190 | return -EIO; |
| 191 | |
| 192 | ret = mt76x0_init_bbp(dev); |
| 193 | if (ret) |
| 194 | return ret; |
| 195 | |
| 196 | dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); |
| 197 | |
| 198 | for (i = 0; i < 16; i++) |
| 199 | for (k = 0; k < 4; k++) |
| 200 | mt76x02_mac_shared_key_setup(dev, i, k, NULL); |
| 201 | |
| 202 | for (i = 0; i < 256; i++) |
| 203 | mt76x02_mac_wcid_setup(dev, i, 0, NULL); |
| 204 | |
| 205 | ret = mt76x0_eeprom_init(dev); |
| 206 | if (ret) |
| 207 | return ret; |
| 208 | |
| 209 | mt76x0_phy_init(dev); |
| 210 | |
| 211 | return 0; |
| 212 | } |
| 213 | EXPORT_SYMBOL_GPL(mt76x0_init_hardware); |
| 214 | |
| 215 | static void |
| 216 | mt76x0_init_txpower(struct mt76x02_dev *dev, |
| 217 | struct ieee80211_supported_band *sband) |
| 218 | { |
| 219 | struct ieee80211_channel *chan; |
| 220 | struct mt76x02_rate_power t; |
| 221 | s8 tp; |
| 222 | int i; |
| 223 | |
| 224 | for (i = 0; i < sband->n_channels; i++) { |
| 225 | chan = &sband->channels[i]; |
| 226 | |
| 227 | mt76x0_get_tx_power_per_rate(dev, chan, &t); |
| 228 | mt76x0_get_power_info(dev, chan, &tp); |
| 229 | |
| 230 | chan->orig_mpwr = (mt76x02_get_max_rate_power(&t) + tp) / 2; |
| 231 | chan->max_power = min_t(int, chan->max_reg_power, |
| 232 | chan->orig_mpwr); |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | int mt76x0_register_device(struct mt76x02_dev *dev) |
| 237 | { |
| 238 | int ret; |
| 239 | |
| 240 | ret = mt76x02_init_device(dev); |
| 241 | if (ret) |
| 242 | return ret; |
| 243 | |
| 244 | mt76x02_config_mac_addr_list(dev); |
| 245 | |
| 246 | ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, |
| 247 | ARRAY_SIZE(mt76x02_rates)); |
| 248 | if (ret) |
| 249 | return ret; |
| 250 | |
| 251 | if (dev->mphy.cap.has_5ghz) { |
| 252 | struct ieee80211_supported_band *sband; |
| 253 | |
| 254 | sband = &dev->mphy.sband_5g.sband; |
| 255 | sband->vht_cap.cap &= ~IEEE80211_VHT_CAP_RXLDPC; |
| 256 | mt76x0_init_txpower(dev, sband); |
| 257 | } |
| 258 | |
| 259 | if (dev->mphy.cap.has_2ghz) |
| 260 | mt76x0_init_txpower(dev, &dev->mphy.sband_2g.sband); |
| 261 | |
| 262 | mt76x02_init_debugfs(dev); |
| 263 | |
| 264 | return 0; |
| 265 | } |
| 266 | EXPORT_SYMBOL_GPL(mt76x0_register_device); |