1134b2d0dSStanislaw Gruszka /* 2134b2d0dSStanislaw Gruszka * (c) Copyright 2002-2010, Ralink Technology, Inc. 3134b2d0dSStanislaw Gruszka * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 4134b2d0dSStanislaw Gruszka * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 5134b2d0dSStanislaw Gruszka * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> 6134b2d0dSStanislaw Gruszka * 7134b2d0dSStanislaw Gruszka * This program is free software; you can redistribute it and/or modify 8134b2d0dSStanislaw Gruszka * it under the terms of the GNU General Public License version 2 9134b2d0dSStanislaw Gruszka * as published by the Free Software Foundation 10134b2d0dSStanislaw Gruszka * 11134b2d0dSStanislaw Gruszka * This program is distributed in the hope that it will be useful, 12134b2d0dSStanislaw Gruszka * but WITHOUT ANY WARRANTY; without even the implied warranty of 13134b2d0dSStanislaw Gruszka * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14134b2d0dSStanislaw Gruszka * GNU General Public License for more details. 15134b2d0dSStanislaw Gruszka */ 16134b2d0dSStanislaw Gruszka 17134b2d0dSStanislaw Gruszka #include "mt76x0.h" 18134b2d0dSStanislaw Gruszka #include "eeprom.h" 19134b2d0dSStanislaw Gruszka #include "mcu.h" 20134b2d0dSStanislaw Gruszka #include "initvals.h" 21134b2d0dSStanislaw Gruszka 221bee323aSLorenzo Bianconi static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) 231bee323aSLorenzo Bianconi { 241bee323aSLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap; 251bee323aSLorenzo Bianconi u16 mcs_map = 0; 261bee323aSLorenzo Bianconi int i; 271bee323aSLorenzo Bianconi 281bee323aSLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC; 291bee323aSLorenzo Bianconi for (i = 0; i < 8; i++) { 301bee323aSLorenzo Bianconi if (!i) 311bee323aSLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2)); 321bee323aSLorenzo Bianconi else 331bee323aSLorenzo Bianconi mcs_map |= 341bee323aSLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 351bee323aSLorenzo Bianconi } 361bee323aSLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 371bee323aSLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 381bee323aSLorenzo Bianconi } 391bee323aSLorenzo Bianconi 40134b2d0dSStanislaw Gruszka static void 41b2d871c0SLorenzo Bianconi mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable) 42134b2d0dSStanislaw Gruszka { 435b394355SLorenzo Bianconi u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD; 44134b2d0dSStanislaw Gruszka 45134b2d0dSStanislaw Gruszka /* Note: we don't turn off WLAN_CLK because that makes the device 46134b2d0dSStanislaw Gruszka * not respond properly on the probe path. 47134b2d0dSStanislaw Gruszka * In case anyone (PSM?) wants to use this function we can 48134b2d0dSStanislaw Gruszka * bring the clock stuff back and fixup the probe path. 49134b2d0dSStanislaw Gruszka */ 50134b2d0dSStanislaw Gruszka 51134b2d0dSStanislaw Gruszka if (enable) 52134b2d0dSStanislaw Gruszka val |= (MT_WLAN_FUN_CTRL_WLAN_EN | 53134b2d0dSStanislaw Gruszka MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 54134b2d0dSStanislaw Gruszka else 55134b2d0dSStanislaw Gruszka val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); 56134b2d0dSStanislaw Gruszka 57134b2d0dSStanislaw Gruszka mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 58134b2d0dSStanislaw Gruszka udelay(20); 59134b2d0dSStanislaw Gruszka 60134b2d0dSStanislaw Gruszka /* Note: vendor driver tries to disable/enable wlan here and retry 61134b2d0dSStanislaw Gruszka * but the code which does it is so buggy it must have never 62134b2d0dSStanislaw Gruszka * triggered, so don't bother. 63134b2d0dSStanislaw Gruszka */ 645b394355SLorenzo Bianconi if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000)) 655b394355SLorenzo Bianconi dev_err(dev->mt76.dev, "PLL and XTAL check failed\n"); 66134b2d0dSStanislaw Gruszka } 67134b2d0dSStanislaw Gruszka 68b2d871c0SLorenzo Bianconi void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset) 69134b2d0dSStanislaw Gruszka { 70134b2d0dSStanislaw Gruszka u32 val; 71134b2d0dSStanislaw Gruszka 72134b2d0dSStanislaw Gruszka val = mt76_rr(dev, MT_WLAN_FUN_CTRL); 73134b2d0dSStanislaw Gruszka 74134b2d0dSStanislaw Gruszka if (reset) { 75134b2d0dSStanislaw Gruszka val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; 76134b2d0dSStanislaw Gruszka val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; 77134b2d0dSStanislaw Gruszka 78134b2d0dSStanislaw Gruszka if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { 79134b2d0dSStanislaw Gruszka val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | 80134b2d0dSStanislaw Gruszka MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 81134b2d0dSStanislaw Gruszka mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 82134b2d0dSStanislaw Gruszka udelay(20); 83134b2d0dSStanislaw Gruszka 84134b2d0dSStanislaw Gruszka val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | 85134b2d0dSStanislaw Gruszka MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 86134b2d0dSStanislaw Gruszka } 87134b2d0dSStanislaw Gruszka } 88134b2d0dSStanislaw Gruszka 89134b2d0dSStanislaw Gruszka mt76_wr(dev, MT_WLAN_FUN_CTRL, val); 90134b2d0dSStanislaw Gruszka udelay(20); 91134b2d0dSStanislaw Gruszka 92134b2d0dSStanislaw Gruszka mt76x0_set_wlan_state(dev, val, enable); 93134b2d0dSStanislaw Gruszka } 94c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); 95134b2d0dSStanislaw Gruszka 96b2d871c0SLorenzo Bianconi static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev) 97134b2d0dSStanislaw Gruszka { 98512bd4b1SLorenzo Bianconi mt76_wr(dev, MT_MAC_SYS_CTRL, 99512bd4b1SLorenzo Bianconi MT_MAC_SYS_CTRL_RESET_CSR | 100134b2d0dSStanislaw Gruszka MT_MAC_SYS_CTRL_RESET_BBP); 101134b2d0dSStanislaw Gruszka msleep(200); 1022b2cb40bSLorenzo Bianconi mt76_clear(dev, MT_MAC_SYS_CTRL, 1032b2cb40bSLorenzo Bianconi MT_MAC_SYS_CTRL_RESET_CSR | 1042b2cb40bSLorenzo Bianconi MT_MAC_SYS_CTRL_RESET_BBP); 105134b2d0dSStanislaw Gruszka } 106134b2d0dSStanislaw Gruszka 107134b2d0dSStanislaw Gruszka #define RANDOM_WRITE(dev, tab) \ 10817507157SLorenzo Bianconi mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ 109f1638c7cSStanislaw Gruszka tab, ARRAY_SIZE(tab)) 110134b2d0dSStanislaw Gruszka 111b2d871c0SLorenzo Bianconi static int mt76x0_init_bbp(struct mt76x02_dev *dev) 112134b2d0dSStanislaw Gruszka { 113134b2d0dSStanislaw Gruszka int ret, i; 114134b2d0dSStanislaw Gruszka 1159c410782SLorenzo Bianconi ret = mt76x0_phy_wait_bbp_ready(dev); 116134b2d0dSStanislaw Gruszka if (ret) 117134b2d0dSStanislaw Gruszka return ret; 118134b2d0dSStanislaw Gruszka 119134b2d0dSStanislaw Gruszka RANDOM_WRITE(dev, mt76x0_bbp_init_tab); 120134b2d0dSStanislaw Gruszka 121134b2d0dSStanislaw Gruszka for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) { 122134b2d0dSStanislaw Gruszka const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i]; 123134b2d0dSStanislaw Gruszka const struct mt76_reg_pair *pair = &item->reg_pair; 124134b2d0dSStanislaw Gruszka 125134b2d0dSStanislaw Gruszka if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20)) 126134b2d0dSStanislaw Gruszka mt76_wr(dev, pair->reg, pair->value); 127134b2d0dSStanislaw Gruszka } 128134b2d0dSStanislaw Gruszka 129134b2d0dSStanislaw Gruszka RANDOM_WRITE(dev, mt76x0_dcoc_tab); 130134b2d0dSStanislaw Gruszka 131134b2d0dSStanislaw Gruszka return 0; 132134b2d0dSStanislaw Gruszka } 133134b2d0dSStanislaw Gruszka 134b2d871c0SLorenzo Bianconi static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) 135134b2d0dSStanislaw Gruszka { 136134b2d0dSStanislaw Gruszka RANDOM_WRITE(dev, common_mac_reg_table); 137134b2d0dSStanislaw Gruszka 138d87cf75fSLorenzo Bianconi mt76x02_set_beacon_offsets(dev); 139134b2d0dSStanislaw Gruszka 140134b2d0dSStanislaw Gruszka /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ 141134b2d0dSStanislaw Gruszka RANDOM_WRITE(dev, mt76x0_mac_reg_table); 142134b2d0dSStanislaw Gruszka 143134b2d0dSStanislaw Gruszka /* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */ 14400eccdd6SLorenzo Bianconi mt76_clear(dev, MT_MAC_SYS_CTRL, 0x3); 145134b2d0dSStanislaw Gruszka 146134b2d0dSStanislaw Gruszka /* Set 0x141C[15:12]=0xF */ 14700eccdd6SLorenzo Bianconi mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); 148134b2d0dSStanislaw Gruszka 149134b2d0dSStanislaw Gruszka mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); 150134b2d0dSStanislaw Gruszka 151134b2d0dSStanislaw Gruszka /* 15200eccdd6SLorenzo Bianconi * tx_ring 9 is for mgmt frame 15300eccdd6SLorenzo Bianconi * tx_ring 8 is for in-band command frame. 15400eccdd6SLorenzo Bianconi * WMM_RG0_TXQMA: this register setting is for FCE to 15500eccdd6SLorenzo Bianconi * define the rule of tx_ring 9 15600eccdd6SLorenzo Bianconi * WMM_RG1_TXQMA: this register setting is for FCE to 15700eccdd6SLorenzo Bianconi * define the rule of tx_ring 8 158134b2d0dSStanislaw Gruszka */ 15900eccdd6SLorenzo Bianconi mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); 160134b2d0dSStanislaw Gruszka } 161134b2d0dSStanislaw Gruszka 162b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_mem(struct mt76x02_dev *dev) 163134b2d0dSStanislaw Gruszka { 164134b2d0dSStanislaw Gruszka u32 *vals; 165331419b2SStanislaw Gruszka int i; 166134b2d0dSStanislaw Gruszka 16736404c06SStanislaw Gruszka vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); 168134b2d0dSStanislaw Gruszka if (!vals) 169134b2d0dSStanislaw Gruszka return -ENOMEM; 170134b2d0dSStanislaw Gruszka 17136404c06SStanislaw Gruszka for (i = 0; i < MT76_N_WCIDS; i++) { 172134b2d0dSStanislaw Gruszka vals[i * 2] = 0xffffffff; 173134b2d0dSStanislaw Gruszka vals[i * 2 + 1] = 0x00ffffff; 174134b2d0dSStanislaw Gruszka } 175134b2d0dSStanislaw Gruszka 176331419b2SStanislaw Gruszka mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2); 177134b2d0dSStanislaw Gruszka kfree(vals); 178331419b2SStanislaw Gruszka return 0; 179134b2d0dSStanislaw Gruszka } 180134b2d0dSStanislaw Gruszka 181b2d871c0SLorenzo Bianconi static void mt76x0_init_key_mem(struct mt76x02_dev *dev) 182134b2d0dSStanislaw Gruszka { 183134b2d0dSStanislaw Gruszka u32 vals[4] = {}; 184134b2d0dSStanislaw Gruszka 185331419b2SStanislaw Gruszka mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals)); 186134b2d0dSStanislaw Gruszka } 187134b2d0dSStanislaw Gruszka 188b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_attr_mem(struct mt76x02_dev *dev) 189134b2d0dSStanislaw Gruszka { 190134b2d0dSStanislaw Gruszka u32 *vals; 191331419b2SStanislaw Gruszka int i; 192134b2d0dSStanislaw Gruszka 19336404c06SStanislaw Gruszka vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); 194134b2d0dSStanislaw Gruszka if (!vals) 195134b2d0dSStanislaw Gruszka return -ENOMEM; 196134b2d0dSStanislaw Gruszka 19736404c06SStanislaw Gruszka for (i = 0; i < MT76_N_WCIDS * 2; i++) 198134b2d0dSStanislaw Gruszka vals[i] = 1; 199134b2d0dSStanislaw Gruszka 200331419b2SStanislaw Gruszka mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2); 201134b2d0dSStanislaw Gruszka kfree(vals); 202331419b2SStanislaw Gruszka return 0; 203134b2d0dSStanislaw Gruszka } 204134b2d0dSStanislaw Gruszka 205b2d871c0SLorenzo Bianconi static void mt76x0_reset_counters(struct mt76x02_dev *dev) 206134b2d0dSStanislaw Gruszka { 207797ea240SStanislaw Gruszka mt76_rr(dev, MT_RX_STAT_0); 208797ea240SStanislaw Gruszka mt76_rr(dev, MT_RX_STAT_1); 209797ea240SStanislaw Gruszka mt76_rr(dev, MT_RX_STAT_2); 210797ea240SStanislaw Gruszka mt76_rr(dev, MT_TX_STA_0); 211797ea240SStanislaw Gruszka mt76_rr(dev, MT_TX_STA_1); 212797ea240SStanislaw Gruszka mt76_rr(dev, MT_TX_STA_2); 213134b2d0dSStanislaw Gruszka } 214134b2d0dSStanislaw Gruszka 215b2d871c0SLorenzo Bianconi int mt76x0_mac_start(struct mt76x02_dev *dev) 216134b2d0dSStanislaw Gruszka { 217134b2d0dSStanislaw Gruszka mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); 218134b2d0dSStanislaw Gruszka 2193b11db26SLorenzo Bianconi if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) 220134b2d0dSStanislaw Gruszka return -ETIMEDOUT; 221134b2d0dSStanislaw Gruszka 222108a4861SStanislaw Gruszka mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 223134b2d0dSStanislaw Gruszka mt76_wr(dev, MT_MAC_SYS_CTRL, 224134b2d0dSStanislaw Gruszka MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); 225134b2d0dSStanislaw Gruszka 2263b11db26SLorenzo Bianconi return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0; 227134b2d0dSStanislaw Gruszka } 228b11e1969SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x0_mac_start); 229134b2d0dSStanislaw Gruszka 230b2d871c0SLorenzo Bianconi void mt76x0_mac_stop(struct mt76x02_dev *dev) 231134b2d0dSStanislaw Gruszka { 232b11e1969SLorenzo Bianconi int i = 200, ok = 0; 233134b2d0dSStanislaw Gruszka 234134b2d0dSStanislaw Gruszka /* Page count on TxQ */ 235134b2d0dSStanislaw Gruszka while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || 236134b2d0dSStanislaw Gruszka (mt76_rr(dev, 0x0a30) & 0x000000ff) || 237134b2d0dSStanislaw Gruszka (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) 238134b2d0dSStanislaw Gruszka msleep(10); 239134b2d0dSStanislaw Gruszka 240134b2d0dSStanislaw Gruszka if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) 241134b2d0dSStanislaw Gruszka dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n"); 242134b2d0dSStanislaw Gruszka 243134b2d0dSStanislaw Gruszka mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | 244134b2d0dSStanislaw Gruszka MT_MAC_SYS_CTRL_ENABLE_TX); 245134b2d0dSStanislaw Gruszka 246134b2d0dSStanislaw Gruszka /* Page count on RxQ */ 247b11e1969SLorenzo Bianconi for (i = 0; i < 200; i++) { 248134b2d0dSStanislaw Gruszka if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && 249134b2d0dSStanislaw Gruszka !mt76_rr(dev, 0x0a30) && 250134b2d0dSStanislaw Gruszka !mt76_rr(dev, 0x0a34)) { 251134b2d0dSStanislaw Gruszka if (ok++ > 5) 252134b2d0dSStanislaw Gruszka break; 253134b2d0dSStanislaw Gruszka continue; 254134b2d0dSStanislaw Gruszka } 255134b2d0dSStanislaw Gruszka msleep(1); 256134b2d0dSStanislaw Gruszka } 257134b2d0dSStanislaw Gruszka 258134b2d0dSStanislaw Gruszka if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) 259134b2d0dSStanislaw Gruszka dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n"); 260134b2d0dSStanislaw Gruszka } 261c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_mac_stop); 262134b2d0dSStanislaw Gruszka 263b2d871c0SLorenzo Bianconi int mt76x0_init_hardware(struct mt76x02_dev *dev) 264134b2d0dSStanislaw Gruszka { 265134b2d0dSStanislaw Gruszka int ret; 266134b2d0dSStanislaw Gruszka 2673b11db26SLorenzo Bianconi if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000)) 268e30a655eSLorenzo Bianconi return -EIO; 269134b2d0dSStanislaw Gruszka 270134b2d0dSStanislaw Gruszka /* Wait for ASIC ready after FW load. */ 271e30a655eSLorenzo Bianconi if (!mt76x02_wait_for_mac(&dev->mt76)) 272e30a655eSLorenzo Bianconi return -ETIMEDOUT; 273134b2d0dSStanislaw Gruszka 274134b2d0dSStanislaw Gruszka mt76x0_reset_csr_bbp(dev); 275499cd0aaSLorenzo Bianconi ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false); 276134b2d0dSStanislaw Gruszka if (ret) 277e30a655eSLorenzo Bianconi return ret; 27830ec9152SLorenzo Bianconi 279134b2d0dSStanislaw Gruszka mt76x0_init_mac_registers(dev); 280134b2d0dSStanislaw Gruszka 2813b11db26SLorenzo Bianconi if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) 282e30a655eSLorenzo Bianconi return -EIO; 283134b2d0dSStanislaw Gruszka 284134b2d0dSStanislaw Gruszka ret = mt76x0_init_bbp(dev); 285134b2d0dSStanislaw Gruszka if (ret) 286e30a655eSLorenzo Bianconi return ret; 287134b2d0dSStanislaw Gruszka 288a31821abSLorenzo Bianconi dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); 289a31821abSLorenzo Bianconi 290134b2d0dSStanislaw Gruszka ret = mt76x0_init_wcid_mem(dev); 291134b2d0dSStanislaw Gruszka if (ret) 292e30a655eSLorenzo Bianconi return ret; 293e30a655eSLorenzo Bianconi 294331419b2SStanislaw Gruszka mt76x0_init_key_mem(dev); 295e30a655eSLorenzo Bianconi 296134b2d0dSStanislaw Gruszka ret = mt76x0_init_wcid_attr_mem(dev); 297134b2d0dSStanislaw Gruszka if (ret) 298e30a655eSLorenzo Bianconi return ret; 299134b2d0dSStanislaw Gruszka 300134b2d0dSStanislaw Gruszka mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | 301134b2d0dSStanislaw Gruszka MT_BEACON_TIME_CFG_SYNC_MODE | 302134b2d0dSStanislaw Gruszka MT_BEACON_TIME_CFG_TBTT_EN | 303134b2d0dSStanislaw Gruszka MT_BEACON_TIME_CFG_BEACON_TX)); 304134b2d0dSStanislaw Gruszka 305134b2d0dSStanislaw Gruszka mt76x0_reset_counters(dev); 306134b2d0dSStanislaw Gruszka 307134b2d0dSStanislaw Gruszka ret = mt76x0_eeprom_init(dev); 308134b2d0dSStanislaw Gruszka if (ret) 309e30a655eSLorenzo Bianconi return ret; 310134b2d0dSStanislaw Gruszka 311134b2d0dSStanislaw Gruszka mt76x0_phy_init(dev); 312134b2d0dSStanislaw Gruszka 313e30a655eSLorenzo Bianconi return 0; 314134b2d0dSStanislaw Gruszka } 315c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_init_hardware); 316134b2d0dSStanislaw Gruszka 317b2d871c0SLorenzo Bianconi struct mt76x02_dev * 318b11e1969SLorenzo Bianconi mt76x0_alloc_device(struct device *pdev, 319b11e1969SLorenzo Bianconi const struct mt76_driver_ops *drv_ops, 320b11e1969SLorenzo Bianconi const struct ieee80211_ops *ops) 321134b2d0dSStanislaw Gruszka { 322b2d871c0SLorenzo Bianconi struct mt76x02_dev *dev; 32395e507d2SLorenzo Bianconi struct mt76_dev *mdev; 324134b2d0dSStanislaw Gruszka 325b11e1969SLorenzo Bianconi mdev = mt76_alloc_device(sizeof(*dev), ops); 32695e507d2SLorenzo Bianconi if (!mdev) 327134b2d0dSStanislaw Gruszka return NULL; 328134b2d0dSStanislaw Gruszka 32995e507d2SLorenzo Bianconi mdev->dev = pdev; 330835123b7SStanislaw Gruszka mdev->drv = drv_ops; 33195e507d2SLorenzo Bianconi 332b2d871c0SLorenzo Bianconi dev = container_of(mdev, struct mt76x02_dev, mt76); 333b2d871c0SLorenzo Bianconi mutex_init(&dev->phy_mutex); 334134b2d0dSStanislaw Gruszka 335134b2d0dSStanislaw Gruszka return dev; 336134b2d0dSStanislaw Gruszka } 337c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_alloc_device); 338134b2d0dSStanislaw Gruszka 339b2d871c0SLorenzo Bianconi int mt76x0_register_device(struct mt76x02_dev *dev) 340134b2d0dSStanislaw Gruszka { 3411bee323aSLorenzo Bianconi struct mt76_dev *mdev = &dev->mt76; 3421bee323aSLorenzo Bianconi struct ieee80211_hw *hw = mdev->hw; 343134b2d0dSStanislaw Gruszka struct wiphy *wiphy = hw->wiphy; 344134b2d0dSStanislaw Gruszka int ret; 345134b2d0dSStanislaw Gruszka 346134b2d0dSStanislaw Gruszka /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to 347134b2d0dSStanislaw Gruszka * entry no. 1 like it does in the vendor driver. 348134b2d0dSStanislaw Gruszka */ 3491bee323aSLorenzo Bianconi mdev->wcid_mask[0] |= 1; 350134b2d0dSStanislaw Gruszka 351134b2d0dSStanislaw Gruszka /* init fake wcid for monitor interfaces */ 3521bee323aSLorenzo Bianconi mdev->global_wcid.idx = 0xff; 3531bee323aSLorenzo Bianconi mdev->global_wcid.hw_key_idx = -1; 354134b2d0dSStanislaw Gruszka 3551bee323aSLorenzo Bianconi /* init antenna configuration */ 3561bee323aSLorenzo Bianconi mdev->antenna_mask = 1; 357134b2d0dSStanislaw Gruszka 358134b2d0dSStanislaw Gruszka hw->queues = 4; 359134b2d0dSStanislaw Gruszka hw->max_rates = 1; 360134b2d0dSStanislaw Gruszka hw->max_report_rates = 7; 361134b2d0dSStanislaw Gruszka hw->max_rate_tries = 1; 362f3727daeSStanislaw Gruszka hw->extra_tx_headroom = 2; 363f3727daeSStanislaw Gruszka if (mt76_is_usb(dev)) 364f3727daeSStanislaw Gruszka hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + 365f3727daeSStanislaw Gruszka MT_DMA_HDR_LEN; 366134b2d0dSStanislaw Gruszka 36716c8a792SStanislaw Gruszka hw->sta_data_size = sizeof(struct mt76x02_sta); 36898ff26e5SStanislaw Gruszka hw->vif_data_size = sizeof(struct mt76x02_vif); 369134b2d0dSStanislaw Gruszka 370134b2d0dSStanislaw Gruszka wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 371134b2d0dSStanislaw Gruszka 37273556561SLorenzo Bianconi INIT_DELAYED_WORK(&dev->mac_work, mt76x02_mac_work); 373134b2d0dSStanislaw Gruszka 3741bee323aSLorenzo Bianconi ret = mt76_register_device(mdev, true, mt76x02_rates, 3751bee323aSLorenzo Bianconi ARRAY_SIZE(mt76x02_rates)); 376134b2d0dSStanislaw Gruszka if (ret) 377134b2d0dSStanislaw Gruszka return ret; 378134b2d0dSStanislaw Gruszka 3791bee323aSLorenzo Bianconi /* overwrite unsupported features */ 3801bee323aSLorenzo Bianconi if (mdev->cap.has_5ghz) 3811bee323aSLorenzo Bianconi mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband); 3821bee323aSLorenzo Bianconi 38363f15d94SLorenzo Bianconi mt76x02_init_debugfs(dev); 384134b2d0dSStanislaw Gruszka 385134b2d0dSStanislaw Gruszka return 0; 386134b2d0dSStanislaw Gruszka } 387c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_register_device); 388