static void mt76_power_on(struct mt76_dev *dev) { u32 val; /* Turn on WL MTCMOS */ mt76_set(dev, MT_WLAN_MTC_CTRL, MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); val = MT_WLAN_MTC_CTRL_STATE_UP | MT_WLAN_MTC_CTRL_PWR_ACK | MT_WLAN_MTC_CTRL_PWR_ACK_S; mt76_poll(dev, MT_WLAN_MTC_CTRL, val, val, 1000); mt76_clear(dev, MT_WLAN_MTC_CTRL, 0x7f << 16); udelay(10); mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xf << 24); udelay(10); mt76_set(dev, MT_WLAN_MTC_CTRL, 0xf << 24); mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xfff); /* Turn on AD/DA power down */ mt76_clear(dev, 0x11204, BIT(3)); /* WLAN function enable */ mt76_set(dev, 0x10080, BIT(0)); /* Release BBP software reset */ mt76_clear(dev, 0x10064, BIT(18)); mt76_power_on_rf(dev, 0); mt76_power_on_rf(dev, 1); }
void mt76_mac_stop(struct mt76_dev *dev, bool force) { bool stopped = false; u32 rts_cfg; int i; mt76_wr(dev, MT_MAC_SYS_CTRL, 0); rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); /* Wait for MAC to become idle */ for (i = 0; i < 300; i++) { if (mt76_rr(dev, MT_MAC_STATUS) & (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) continue; if (mt76_rr(dev, MT_BBP(IBI, 12))) continue; stopped = true; break; } if (force && !stopped) { mt76_set(dev, MT_BBP(CORE, 4), BIT(2)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(2)); mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); } mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); }
int mt76x2u_mac_reset(struct mt76x02_dev *dev) { mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5)); /* init pbf regs */ mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); mt76_write_mac_initvals(dev); mt76_wr(dev, MT_TX_LINK_CFG, 0x1020); mt76_wr(dev, MT_AUTO_RSP_CFG, 0x13); mt76_wr(dev, MT_MAX_LEN_CFG, 0x2f00); mt76_wr(dev, MT_TX_RTS_CFG, 0x92b20); mt76_wr(dev, MT_WMM_AIFSN, 0x2273); mt76_wr(dev, MT_WMM_CWMIN, 0x2344); mt76_wr(dev, MT_WMM_CWMAX, 0x34aa); mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | MT_MAC_SYS_CTRL_RESET_BBP); if (is_mt7612(dev)) mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); mt76_set(dev, MT_EXT_CCA_CFG, 0xf000); mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); mt76x2u_mac_fixup_xtal(dev); return 0; }
static int mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x0_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; int ret = 0; int idx = 0; mutex_lock(&dev->mutex); idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); if (idx < 0) { ret = -ENOSPC; goto out; } msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; mt76x0_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); rcu_assign_pointer(dev->wcid[idx], &msta->wcid); mt76x0_mac_set_ampdu_factor(dev); out: mutex_unlock(&dev->mutex); return ret; }
static int mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { struct mt7601u_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; WARN_ON(msta->wcid.idx > GROUP_WCID(0)); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: break; case IEEE80211_AMPDU_TX_START: msta->agg_ssn[tid] = *ssn << 4; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } return 0; }
int mt76_mac_start(struct mt76_dev *dev) { int i; for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_AGG_CNT(i)); for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); wait_for_wpdma(dev); udelay(50); mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); mt76_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | MT_INT_TX_STAT); return 0; }
static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) { int i, ok; if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) return; mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX); if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) dev_warn(dev->dev, "Warning: TX DMA did not stop!\n"); /* Page count on TxQ */ i = 200; while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || (mt76_rr(dev, 0x0a30) & 0x000000ff) || (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) msleep(10); if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) dev_warn(dev->dev, "Warning: MAC TX did not stop!\n"); mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | MT_MAC_SYS_CTRL_ENABLE_TX); /* Page count on RxQ */ ok = 0; i = 200; while (i--) { if ((mt76_rr(dev, 0x0430) & 0x00ff0000) || (mt76_rr(dev, 0x0a30) & 0xffffffff) || (mt76_rr(dev, 0x0a34) & 0xffffffff)) ok++; if (ok > 6) break; msleep(1); } if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) dev_warn(dev->dev, "Warning: MAC RX did not stop!\n"); if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) dev_warn(dev->dev, "Warning: RX DMA did not stop!\n"); }
static void mt76_set_tx_dac(struct mt76_dev *dev) { if (dev->chainmask & BIT(1)) mt76_set(dev, MT_BBP(TXBE, 5), 3); else mt76_clear(dev, MT_BBP(TXBE, 5), 3); }
static void mt76_phy_set_band(struct mt76_dev *dev, int band, bool primary_upper) { switch (band) { case IEEE80211_BAND_2GHZ: mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); break; case IEEE80211_BAND_5GHZ: mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); break; } mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, primary_upper); }
void mt76x2_phy_set_antenna(struct mt76x02_dev *dev) { u32 val; val = mt76_rr(dev, MT_BBP(AGC, 0)); val &= ~(BIT(4) | BIT(1)); switch (dev->mt76.antenna_mask) { case 1: /* disable mac DAC control */ mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); mt76_clear(dev, MT_BBP(TXBE, 5), 3); mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0x3); mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 2); /* disable DAC 1 */ mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 4); val &= ~(BIT(3) | BIT(0)); break; case 2: /* disable mac DAC control */ mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); mt76_rmw_field(dev, MT_BBP(TXBE, 5), 3, 1); mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xc); mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 1); /* disable DAC 0 */ mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 1); val &= ~BIT(3); val |= BIT(0); break; case 3: default: /* enable mac DAC control */ mt76_set(dev, MT_BBP(IBI, 9), BIT(11)); mt76_set(dev, MT_BBP(TXBE, 5), 3); mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xf); mt76_clear(dev, MT_BBP(CORE, 32), GENMASK(21, 20)); mt76_clear(dev, MT_BBP(CORE, 33), GENMASK(12, 9)); val &= ~BIT(0); val |= BIT(3); break; } mt76_wr(dev, MT_BBP(AGC, 0), val); }
static void mt76_power_on_rf_patch(struct mt76_dev *dev) { mt76_set(dev, 0x10130, BIT(0) | BIT(16)); udelay(1); mt76_clear(dev, 0x1001c, 0xff); mt76_set(dev, 0x1001c, 0x30); mt76_wr(dev, 0x10014, 0x484f); udelay(1); mt76_set(dev, 0x10130, BIT(17)); udelay(125); mt76_clear(dev, 0x10130, BIT(16)); udelay(50); mt76_set(dev, 0x1014c, BIT(19) | BIT(20)); }
static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) { s8 offset = 0; u16 eep_val; eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2); offset = eep_val & 0x7f; if ((eep_val & 0xff) == 0xff) offset = 0; else if (eep_val & 0x80) offset = 0 - offset; eep_val >>= 8; if (eep_val == 0x00 || eep_val == 0xff) { eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1); eep_val &= 0xff; if (eep_val == 0x00 || eep_val == 0xff) eep_val = 0x14; } eep_val &= 0x7f; mt76_rmw_field(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL5), MT_XO_CTRL5_C2_VAL, eep_val + offset); mt76_set(dev, MT_VEND_ADDR(CFG, MT_XO_CTRL6), MT_XO_CTRL6_C2_CTRL); mt76_wr(dev, 0x504, 0x06000000); mt76_wr(dev, 0x50c, 0x08800000); mdelay(5); mt76_wr(dev, 0x504, 0x0); /* decrease SIFS from 16us to 13us */ mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 0xd); mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, MT_BKOFF_SLOT_CFG_CC_DELAY, 1); /* init fce */ mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { case 0: mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); break; case 1: mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); break; default: break; } }
int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct ieee80211_sta *sta = params->sta; struct mt76x02_dev *dev = hw->priv; struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; struct mt76_txq *mtxq; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn, params->buf_size); mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = *ssn << 4; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } return 0; }
void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force) { bool stopped = false; u32 rts_cfg; int i; mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); mt76_clear(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN); mt76_wr(dev, MT_MAC_SYS_CTRL, 0); rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); /* Wait for MAC to become idle */ for (i = 0; i < 300; i++) { if ((mt76_rr(dev, MT_MAC_STATUS) & (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || mt76_rr(dev, MT_BBP(IBI, 12))) { udelay(1); continue; } stopped = true; break; } if (force && !stopped) { mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); } mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); }
static int mt76x2u_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { int err; cancel_delayed_work_sync(&dev->cal_work); set_bit(MT76_RESET, &dev->mt76.state); mt76_set_channel(&dev->mt76); mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); mt76x2_mac_stop(dev, false); err = mt76x2u_phy_set_channel(dev, chandef); mt76x2u_mac_resume(dev); clear_bit(MT76_RESET, &dev->mt76.state); mt76_txq_schedule_all(&dev->mt76); return err; }
static void mt76_mac_pbf_init(struct mt76_dev *dev) { u32 val; val = MT_PBF_SYS_CTRL_MCU_RESET | MT_PBF_SYS_CTRL_DMA_RESET | MT_PBF_SYS_CTRL_MAC_RESET | MT_PBF_SYS_CTRL_PBF_RESET | MT_PBF_SYS_CTRL_ASY_RESET; mt76_set(dev, MT_PBF_SYS_CTRL, val); mt76_clear(dev, MT_PBF_SYS_CTRL, val); mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); }
static void mt76_power_on_rf(struct mt76_dev *dev, int unit) { int shift = unit ? 8 : 0; /* Enable RF BG */ mt76_set(dev, 0x10130, BIT(0) << shift); udelay(10); /* Enable RFDIG LDO/AFE/ABB/ADDA */ mt76_set(dev, 0x10130, (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift); udelay(10); /* Switch RFDIG power to internal LDO */ mt76_clear(dev, 0x10130, BIT(2) << shift); udelay(10); mt76_power_on_rf_patch(dev); mt76_set(dev, 0x530, 0xf); }
static int mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta,u16 tid, u16 *ssn, u8 buf_size) { struct mt76_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; struct ieee80211_txq *txq = sta->txq[tid]; struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; if (!txq) return -EINVAL; switch (action) { case IEEE80211_AMPDU_RX_START: mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx)+4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx)+4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ieee80211_send_bar(vif, sta->addr, tid, cpu_to_le16(mtxq->agg_ssn)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = *ssn << 4; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } return 0; }
static int mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { struct mt76x0_dev *dev = hw->priv; struct ieee80211_sta *sta = params->sta; enum ieee80211_ampdu_mlme_action action = params->action; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; WARN_ON(msta->wcid.idx > N_WCIDS); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: break; case IEEE80211_AMPDU_TX_START: msta->agg_ssn[tid] = *ssn << 4; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } return 0; }
void mt76x02_init_beacon_config(struct mt76x02_dev *dev) { int i; if (mt76_is_mmio(dev)) { /* Fire a pre-TBTT interrupt 8 ms before TBTT */ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, MT_DFS_GP_INTERVAL); mt76_wr(dev, MT_INT_TIMER_EN, 0); } mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX)); mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); for (i = 0; i < 8; i++) mt76x02_mac_set_beacon(dev, i, NULL); mt76x02_set_beacon_offsets(dev); }
static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) { static const u8 null_addr[ETH_ALEN] = {}; const u8 *macaddr = dev->mt76.macaddr; u32 val; int i, k; if (!mt76x2_wait_for_mac(dev)) return -ETIMEDOUT; val = mt76_rr(dev, MT_WPDMA_GLO_CFG); val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_BUSY | MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); val |= FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); mt76_wr(dev, MT_WPDMA_GLO_CFG, val); mt76x2_mac_pbf_init(dev); mt76_write_mac_initvals(dev); mt76x2_fixup_xtal(dev); mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | MT_MAC_SYS_CTRL_RESET_BBP); if (is_mt7612(dev)) mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); usleep_range(5000, 10000); mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(macaddr)); mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(macaddr + 4)); mt76_wr(dev, MT_MAC_BSSID_DW0, get_unaligned_le32(macaddr)); mt76_wr(dev, MT_MAC_BSSID_DW1, get_unaligned_le16(macaddr + 4) | FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); /* Fire a pre-TBTT interrupt 8 ms before TBTT */ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, MT_DFS_GP_INTERVAL); mt76_wr(dev, MT_INT_TIMER_EN, 0); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); if (!hard) return 0; for (i = 0; i < 256 / 32; i++) mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); for (i = 0; i < 256; i++) mt76x2_mac_wcid_setup(dev, i, 0, NULL); for (i = 0; i < MT_MAX_VIFS; i++) mt76x2_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL); for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) mt76x2_mac_shared_key_setup(dev, i, k, NULL); for (i = 0; i < 8; i++) { mt76x2_mac_set_bssid(dev, i, null_addr); mt76x2_mac_set_beacon(dev, i, NULL); } for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); mt76_wr(dev, MT_CH_TIME_CFG, MT_CH_TIME_CFG_TIMER_EN | MT_CH_TIME_CFG_TX_AS_BUSY | MT_CH_TIME_CFG_RX_AS_BUSY | MT_CH_TIME_CFG_NAV_AS_BUSY | MT_CH_TIME_CFG_EIFS_AS_BUSY | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); mt76x2_init_beacon_offsets(dev); mt76x2_set_tx_ackto(dev); return 0; }
int mt76x2u_mac_stop(struct mt76x02_dev *dev) { int i, count = 0, val; bool stopped = false; u32 rts_cfg; if (test_bit(MT76_REMOVED, &dev->mt76.state)) return -EIO; rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); /* wait tx dma to stop */ for (i = 0; i < 2000; i++) { val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); if (!(val & MT_USB_DMA_CFG_TX_BUSY) && i > 10) break; usleep_range(50, 100); } /* page count on TxQ */ for (i = 0; i < 200; i++) { if (!(mt76_rr(dev, 0x0438) & 0xffffffff) && !(mt76_rr(dev, 0x0a30) & 0x000000ff) && !(mt76_rr(dev, 0x0a34) & 0xff00ff00)) break; usleep_range(10, 20); } /* disable tx-rx */ mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | MT_MAC_SYS_CTRL_ENABLE_TX); /* Wait for MAC to become idle */ for (i = 0; i < 1000; i++) { if (!(mt76_rr(dev, MT_MAC_STATUS) & MT_MAC_STATUS_TX) && !mt76_rr(dev, MT_BBP(IBI, 12))) { stopped = true; break; } usleep_range(10, 20); } if (!stopped) { mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); } /* page count on RxQ */ for (i = 0; i < 200; i++) { if (!(mt76_rr(dev, 0x0430) & 0x00ff0000) && !(mt76_rr(dev, 0x0a30) & 0xffffffff) && !(mt76_rr(dev, 0x0a34) & 0xffffffff) && ++count > 10) break; msleep(50); } if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 2000)) dev_warn(dev->mt76.dev, "MAC RX failed to stop\n"); /* wait rx dma to stop */ for (i = 0; i < 2000; i++) { val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); if (!(val & MT_USB_DMA_CFG_RX_BUSY) && i > 10) break; usleep_range(50, 100); } mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); return 0; }
static int mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) { struct { __le32 addr; __le32 len; __le32 mode; } req = { .addr = cpu_to_le32(addr), .len = cpu_to_le32(len), .mode = cpu_to_le32(BIT(31)), }; struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, MCU_Q_NA); } static int mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len) { struct sk_buff *skb; int ret = 0; while (len > 0) { int cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd), len); skb = mt7603_mcu_msg_alloc(data, cur_len); if (!skb) return -ENOMEM; ret = __mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER, MCU_Q_NA, NULL); if (ret) break; data += cur_len; len -= cur_len; } return ret; } static int mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) { struct { __le32 override; __le32 addr; } req = { .override = cpu_to_le32(addr ? 1 : 0), .addr = cpu_to_le32(addr), }; struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ, MCU_Q_NA); } static int mt7603_mcu_restart(struct mt7603_dev *dev) { struct sk_buff *skb = mt7603_mcu_msg_alloc(NULL, 0); return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_RESTART_DL_REQ, MCU_Q_NA); } static int mt7603_load_firmware(struct mt7603_dev *dev) { const struct firmware *fw; const struct mt7603_fw_trailer *hdr; const char *firmware; int dl_len; u32 addr, val; int ret; if (is_mt7628(dev)) { if (mt76xx_rev(dev) == MT7628_REV_E1) firmware = MT7628_FIRMWARE_E1; else firmware = MT7628_FIRMWARE_E2; } else { if (mt76xx_rev(dev) < MT7603_REV_E2) firmware = MT7603_FIRMWARE_E1; else firmware = MT7603_FIRMWARE_E2; } ret = request_firmware(&fw, firmware, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver); dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date); addr = mt7603_reg_map(dev, 0x50012498); mt76_wr(dev, addr, 0x5); mt76_wr(dev, addr, 0x5); udelay(1); /* switch to bypass mode */ mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5)); val = mt76_rr(dev, MT_TOP_MISC2); if (val & BIT(1)) { dev_info(dev->mt76.dev, "Firmware already running...\n"); goto running; } if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) { dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n"); ret = -EIO; goto out; } dl_len = le32_to_cpu(hdr->dl_len) + 4; ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); if (ret) { dev_err(dev->mt76.dev, "Download request failed\n"); goto out; } ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len); if (ret) { dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); goto out; } ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); if (ret) { dev_err(dev->mt76.dev, "Failed to start firmware\n"); goto out; } if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); ret = -EIO; goto out; } running: mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); mt76_set(dev, MT_SCH_4, BIT(8)); mt76_clear(dev, MT_SCH_4, BIT(8)); dev->mcu_running = true; dev_info(dev->mt76.dev, "firmware init done\n"); out: release_firmware(fw); return ret; } int mt7603_mcu_init(struct mt7603_dev *dev) { mutex_init(&dev->mt76.mmio.mcu.mutex); return mt7603_load_firmware(dev); }
int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) { const u8 *macaddr = dev->mt76.macaddr; u32 val; int i, k; if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; val = mt76_rr(dev, MT_WPDMA_GLO_CFG); val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_BUSY | MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); val |= FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); mt76_wr(dev, MT_WPDMA_GLO_CFG, val); mt76x2_mac_pbf_init(dev); mt76_write_mac_initvals(dev); mt76x2_fixup_xtal(dev); mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | MT_MAC_SYS_CTRL_RESET_BBP); if (is_mt7612(dev)) mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); usleep_range(5000, 10000); mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); mt76x02_mac_setaddr(dev, macaddr); mt76x02_init_beacon_config(dev); if (!hard) return 0; for (i = 0; i < 256 / 32; i++) mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); for (i = 0; i < 256; i++) { mt76x02_mac_wcid_setup(dev, i, 0, NULL); mt76_wr(dev, MT_WCID_TX_RATE(i), 0); mt76_wr(dev, MT_WCID_TX_RATE(i) + 4, 0); } for (i = 0; i < MT_MAX_VIFS; i++) mt76x02_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL); for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) mt76x02_mac_shared_key_setup(dev, i, k, NULL); for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); mt76_wr(dev, MT_CH_TIME_CFG, MT_CH_TIME_CFG_TIMER_EN | MT_CH_TIME_CFG_TX_AS_BUSY | MT_CH_TIME_CFG_RX_AS_BUSY | MT_CH_TIME_CFG_NAV_AS_BUSY | MT_CH_TIME_CFG_EIFS_AS_BUSY | MT_CH_CCA_RC_EN | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); mt76x02_set_tx_ackto(dev); return 0; }
int mt7601u_init_hardware(struct mt7601u_dev *dev) { static const u16 beacon_offsets[16] = { /* 512 byte per beacon */ 0xc000, 0xc200, 0xc400, 0xc600, 0xc800, 0xca00, 0xcc00, 0xce00, 0xd000, 0xd200, 0xd400, 0xd600, 0xd800, 0xda00, 0xdc00, 0xde00 }; int ret; dev->beacon_offsets = beacon_offsets; mt7601u_chip_onoff(dev, true, false); ret = mt7601u_wait_asic_ready(dev); if (ret) goto err; ret = mt7601u_mcu_init(dev); if (ret) goto err; if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { ret = -EIO; goto err; } /* Wait for ASIC ready after FW load. */ ret = mt7601u_wait_asic_ready(dev); if (ret) goto err; mt7601u_reset_csr_bbp(dev); mt7601u_init_usb_dma(dev); ret = mt7601u_mcu_cmd_init(dev); if (ret) goto err; ret = mt7601u_dma_init(dev); if (ret) goto err_mcu; ret = mt7601u_write_mac_initvals(dev); if (ret) goto err_rx; if (!mt76_poll_msec(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) { ret = -EIO; goto err_rx; } ret = mt7601u_init_bbp(dev); if (ret) goto err_rx; ret = mt7601u_init_wcid_mem(dev); if (ret) goto err_rx; ret = mt7601u_init_key_mem(dev); if (ret) goto err_rx; ret = mt7601u_init_wcid_attr_mem(dev); if (ret) goto err_rx; mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX)); mt7601u_reset_counters(dev); mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); mt7601u_wr(dev, MT_TXOP_CTRL_CFG, FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); ret = mt7601u_eeprom_init(dev); if (ret) goto err_rx; ret = mt7601u_phy_init(dev); if (ret) goto err_rx; mt7601u_set_rx_path(dev, 0); mt7601u_set_tx_dac(dev, 0); mt7601u_mac_set_ctrlch(dev, false); mt7601u_bbp_set_ctrlch(dev, false); mt7601u_bbp_set_bw(dev, MT_BW_20); return 0; err_rx: mt7601u_dma_cleanup(dev); err_mcu: mt7601u_mcu_cmd_deinit(dev); err: mt7601u_chip_onoff(dev, false, false); return ret; }
int mt76_mac_reset(struct mt76_dev *dev, bool hard) { static const u8 null_addr[ETH_ALEN] = {}; u32 val; int i, k; if (!mt76_wait_for_mac(dev)) return -ETIMEDOUT; val = mt76_rr(dev, MT_WPDMA_GLO_CFG); val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_BUSY | MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); val |= MT76_SET(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); mt76_wr(dev, MT_WPDMA_GLO_CFG, val); mt76_mac_pbf_init(dev); mt76_write_mac_initvals(dev); mt76_fixup_xtal(dev); mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | MT_MAC_SYS_CTRL_RESET_BBP); if (is_mt7612(dev)) mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); msleep(5); mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4)); mt76_wr(dev, MT_MAC_BSSID_DW0, get_unaligned_le32(dev->macaddr)); mt76_wr(dev, MT_MAC_BSSID_DW1, get_unaligned_le16(dev->macaddr + 4) | MT76_SET(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); /* Fire a pre-TBTT interrupt 8 ms before TBTT */ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); mt76_wr(dev, MT_INT_TIMER_EN, 0); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); if (!hard) return 0; for (i = 0; i < 256; i++) mt76_mac_wcid_setup(dev, i, 0, NULL); for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) mt76_mac_shared_key_setup(dev, i, k, NULL); for (i = 0; i < 8; i++) { mt76_mac_set_bssid(dev, i, null_addr); mt76_mac_set_beacon(dev, i, NULL); } for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); mt76_set(dev, MT_MAC_APC_BSSID_H(0), MT_MAC_APC_BSSID0_H_EN); mt76_init_beacon_offsets(dev); return 0; }
int mt76_mcu_set_channel(struct mt76_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan) { struct sk_buff *skb; struct { u8 idx; u8 scan; u8 bw; u8 _pad0; __le16 chainmask; u8 ext_chan; u8 _pad1; } __packed __aligned(4) msg = { .idx = channel, .scan = scan, .bw = bw, .chainmask = cpu_to_le16(dev->chainmask), }; /* first set the channel without the extension channel info */ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); mt76_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); msleep(5); msg.ext_chan = 0xe0 + bw_index; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); return mt76_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); } int mt76_mcu_set_radio_state(struct mt76_dev *dev, bool on) { struct sk_buff *skb; struct { __le32 mode; __le32 level; } __packed __aligned(4) msg = { .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), .level = cpu_to_le32(0), }; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); return mt76_mcu_msg_send(dev, skb, CMD_POWER_SAVING_OP); } int mt76_mcu_calibrate(struct mt76_dev *dev, enum mcu_calibration type, u32 param) { struct sk_buff *skb; struct { __le32 id; __le32 value; } __packed __aligned(4) msg = { .id = cpu_to_le32(type), .value = cpu_to_le32(param), }; int ret; mt76_clear(dev, MT_MCU_COM_REG0, BIT(31)); skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); ret = mt76_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); if (ret) return ret; if (WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0, BIT(31), BIT(31), 100))) return -ETIMEDOUT; return 0; } int mt76_mcu_tssi_comp(struct mt76_dev *dev, struct mt76_tssi_comp *tssi_data) { struct sk_buff *skb; struct { __le32 id; struct mt76_tssi_comp data; } __packed __aligned(4) msg = { .id = cpu_to_le32(MCU_CAL_TSSI_COMP), .data = *tssi_data, }; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); return mt76_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); } int mt76_mcu_init_gain(struct mt76_dev *dev, u8 channel, u32 gain, bool force) { struct sk_buff *skb; struct { __le32 channel; __le32 gain_val; } __packed __aligned(4) msg = { .channel = cpu_to_le32(channel), .gain_val = cpu_to_le32(gain), }; if (force) msg.channel |= cpu_to_le32(BIT(31)); skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); return mt76_mcu_msg_send(dev, skb, CMD_INIT_GAIN_OP); } int mt76_mcu_init(struct mt76_dev *dev) { int ret; mutex_init(&dev->mcu.mutex); ret = mt76pci_load_rom_patch(dev); if (ret) return ret; ret = mt76pci_load_firmware(dev); if (ret) return ret; mt76_mcu_function_select(dev, Q_SELECT, 1); return 0; } int mt76_mcu_cleanup(struct mt76_dev *dev) { mt76_wr(dev, MT_MCU_INT_LEVEL, 1); msleep(20); return 0; }