developer | 0f312e8 | 2022-11-01 12:31:52 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: ISC |
| 2 | /* |
| 3 | * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> |
| 4 | */ |
| 5 | |
| 6 | #include <linux/delay.h> |
| 7 | |
| 8 | #include "mt76x2u.h" |
| 9 | #include "eeprom.h" |
| 10 | #include "../mt76x02_phy.h" |
| 11 | #include "../mt76x02_usb.h" |
| 12 | |
| 13 | static void mt76x2u_init_dma(struct mt76x02_dev *dev) |
| 14 | { |
| 15 | u32 val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); |
| 16 | |
| 17 | val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD | |
| 18 | MT_USB_DMA_CFG_RX_BULK_EN | |
| 19 | MT_USB_DMA_CFG_TX_BULK_EN; |
| 20 | |
| 21 | /* disable AGGR_BULK_RX in order to receive one |
| 22 | * frame in each rx urb and avoid copies |
| 23 | */ |
| 24 | val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN; |
| 25 | mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); |
| 26 | } |
| 27 | |
| 28 | static void mt76x2u_power_on_rf_patch(struct mt76x02_dev *dev) |
| 29 | { |
| 30 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) | BIT(16)); |
| 31 | udelay(1); |
| 32 | |
| 33 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1c), 0xff); |
| 34 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x1c), 0x30); |
| 35 | |
| 36 | mt76_wr(dev, MT_VEND_ADDR(CFG, 0x14), 0x484f); |
| 37 | udelay(1); |
| 38 | |
| 39 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(17)); |
| 40 | usleep_range(150, 200); |
| 41 | |
| 42 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(16)); |
| 43 | usleep_range(50, 100); |
| 44 | |
| 45 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x14c), BIT(19) | BIT(20)); |
| 46 | } |
| 47 | |
| 48 | static void mt76x2u_power_on_rf(struct mt76x02_dev *dev, int unit) |
| 49 | { |
| 50 | int shift = unit ? 8 : 0; |
| 51 | u32 val = (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift; |
| 52 | |
| 53 | /* Enable RF BG */ |
| 54 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) << shift); |
| 55 | usleep_range(10, 20); |
| 56 | |
| 57 | /* Enable RFDIG LDO/AFE/ABB/ADDA */ |
| 58 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), val); |
| 59 | usleep_range(10, 20); |
| 60 | |
| 61 | /* Switch RFDIG power to internal LDO */ |
| 62 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x130), BIT(2) << shift); |
| 63 | usleep_range(10, 20); |
| 64 | |
| 65 | mt76x2u_power_on_rf_patch(dev); |
| 66 | |
| 67 | mt76_set(dev, 0x530, 0xf); |
| 68 | } |
| 69 | |
| 70 | static void mt76x2u_power_on(struct mt76x02_dev *dev) |
| 71 | { |
| 72 | u32 val; |
| 73 | |
| 74 | /* Turn on WL MTCMOS */ |
| 75 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), |
| 76 | MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); |
| 77 | |
| 78 | val = MT_WLAN_MTC_CTRL_STATE_UP | |
| 79 | MT_WLAN_MTC_CTRL_PWR_ACK | |
| 80 | MT_WLAN_MTC_CTRL_PWR_ACK_S; |
| 81 | |
| 82 | mt76_poll(dev, MT_VEND_ADDR(CFG, 0x148), val, val, 1000); |
| 83 | |
| 84 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0x7f << 16); |
| 85 | usleep_range(10, 20); |
| 86 | |
| 87 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); |
| 88 | usleep_range(10, 20); |
| 89 | |
| 90 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x148), 0xf << 24); |
| 91 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x148), 0xfff); |
| 92 | |
| 93 | /* Turn on AD/DA power down */ |
| 94 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x1204), BIT(3)); |
| 95 | |
| 96 | /* WLAN function enable */ |
| 97 | mt76_set(dev, MT_VEND_ADDR(CFG, 0x80), BIT(0)); |
| 98 | |
| 99 | /* Release BBP software reset */ |
| 100 | mt76_clear(dev, MT_VEND_ADDR(CFG, 0x64), BIT(18)); |
| 101 | |
| 102 | mt76x2u_power_on_rf(dev, 0); |
| 103 | mt76x2u_power_on_rf(dev, 1); |
| 104 | } |
| 105 | |
| 106 | static int mt76x2u_init_eeprom(struct mt76x02_dev *dev) |
| 107 | { |
| 108 | u32 val, i; |
| 109 | |
| 110 | dev->mt76.eeprom.data = devm_kzalloc(dev->mt76.dev, |
| 111 | MT7612U_EEPROM_SIZE, |
| 112 | GFP_KERNEL); |
| 113 | dev->mt76.eeprom.size = MT7612U_EEPROM_SIZE; |
| 114 | if (!dev->mt76.eeprom.data) |
| 115 | return -ENOMEM; |
| 116 | |
| 117 | for (i = 0; i + 4 <= MT7612U_EEPROM_SIZE; i += 4) { |
| 118 | val = mt76_rr(dev, MT_VEND_ADDR(EEPROM, i)); |
| 119 | put_unaligned_le32(val, dev->mt76.eeprom.data + i); |
| 120 | } |
| 121 | |
| 122 | mt76x02_eeprom_parse_hw_cap(dev); |
| 123 | return 0; |
| 124 | } |
| 125 | |
| 126 | int mt76x2u_init_hardware(struct mt76x02_dev *dev) |
| 127 | { |
| 128 | int i, k, err; |
| 129 | |
| 130 | mt76x2_reset_wlan(dev, true); |
| 131 | mt76x2u_power_on(dev); |
| 132 | |
| 133 | if (!mt76x02_wait_for_mac(&dev->mt76)) |
| 134 | return -ETIMEDOUT; |
| 135 | |
| 136 | err = mt76x2u_mcu_fw_init(dev); |
| 137 | if (err < 0) |
| 138 | return err; |
| 139 | |
| 140 | if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, |
| 141 | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | |
| 142 | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) |
| 143 | return -EIO; |
| 144 | |
| 145 | /* wait for asic ready after fw load. */ |
| 146 | if (!mt76x02_wait_for_mac(&dev->mt76)) |
| 147 | return -ETIMEDOUT; |
| 148 | |
| 149 | mt76x2u_init_dma(dev); |
| 150 | |
| 151 | err = mt76x2u_mcu_init(dev); |
| 152 | if (err < 0) |
| 153 | return err; |
| 154 | |
| 155 | err = mt76x2u_mac_reset(dev); |
| 156 | if (err < 0) |
| 157 | return err; |
| 158 | |
| 159 | mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); |
| 160 | dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); |
| 161 | |
| 162 | if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) |
| 163 | return -ETIMEDOUT; |
| 164 | |
| 165 | /* reset wcid table */ |
| 166 | for (i = 0; i < 256; i++) |
| 167 | mt76x02_mac_wcid_setup(dev, i, 0, NULL); |
| 168 | |
| 169 | /* reset shared key table and pairwise key table */ |
| 170 | for (i = 0; i < 16; i++) { |
| 171 | for (k = 0; k < 4; k++) |
| 172 | mt76x02_mac_shared_key_setup(dev, i, k, NULL); |
| 173 | } |
| 174 | |
| 175 | mt76x02u_init_beacon_config(dev); |
| 176 | |
| 177 | mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); |
| 178 | mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f); |
| 179 | |
| 180 | err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); |
| 181 | if (err < 0) |
| 182 | return err; |
| 183 | |
| 184 | mt76x02_phy_set_rxpath(dev); |
| 185 | mt76x02_phy_set_txdac(dev); |
| 186 | |
| 187 | return mt76x2u_mac_stop(dev); |
| 188 | } |
| 189 | |
| 190 | int mt76x2u_register_device(struct mt76x02_dev *dev) |
| 191 | { |
| 192 | struct ieee80211_hw *hw = mt76_hw(dev); |
| 193 | struct mt76_usb *usb = &dev->mt76.usb; |
| 194 | int err; |
| 195 | |
| 196 | INIT_DELAYED_WORK(&dev->cal_work, mt76x2u_phy_calibrate); |
| 197 | err = mt76x02_init_device(dev); |
| 198 | if (err) |
| 199 | return err; |
| 200 | |
| 201 | err = mt76x2u_init_eeprom(dev); |
| 202 | if (err < 0) |
| 203 | return err; |
| 204 | |
| 205 | usb->mcu.data = devm_kmalloc(dev->mt76.dev, MCU_RESP_URB_SIZE, |
| 206 | GFP_KERNEL); |
| 207 | if (!usb->mcu.data) |
| 208 | return -ENOMEM; |
| 209 | |
| 210 | err = mt76u_alloc_queues(&dev->mt76); |
| 211 | if (err < 0) |
| 212 | goto fail; |
| 213 | |
| 214 | err = mt76x2u_init_hardware(dev); |
| 215 | if (err < 0) |
| 216 | goto fail; |
| 217 | |
| 218 | /* check hw sg support in order to enable AMSDU */ |
| 219 | hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_TX_SG_MAX_SIZE : 1; |
| 220 | err = mt76_register_device(&dev->mt76, true, mt76x02_rates, |
| 221 | ARRAY_SIZE(mt76x02_rates)); |
| 222 | if (err) |
| 223 | goto fail; |
| 224 | |
| 225 | set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); |
| 226 | |
| 227 | mt76x02_init_debugfs(dev); |
| 228 | mt76x2_init_txpower(dev, &dev->mphy.sband_2g.sband); |
| 229 | mt76x2_init_txpower(dev, &dev->mphy.sband_5g.sband); |
| 230 | |
| 231 | return 0; |
| 232 | |
| 233 | fail: |
| 234 | mt76x2u_cleanup(dev); |
| 235 | return err; |
| 236 | } |
| 237 | |
| 238 | void mt76x2u_stop_hw(struct mt76x02_dev *dev) |
| 239 | { |
| 240 | cancel_delayed_work_sync(&dev->cal_work); |
| 241 | cancel_delayed_work_sync(&dev->mphy.mac_work); |
| 242 | mt76x2u_mac_stop(dev); |
| 243 | } |
| 244 | |
| 245 | void mt76x2u_cleanup(struct mt76x02_dev *dev) |
| 246 | { |
| 247 | mt76x02_mcu_set_radio_state(dev, false); |
| 248 | mt76x2u_stop_hw(dev); |
| 249 | mt76u_queues_deinit(&dev->mt76); |
| 250 | } |