104b8e659SRyder Lee // SPDX-License-Identifier: ISC
204b8e659SRyder Lee /* Copyright (C) 2019 MediaTek Inc.
304b8e659SRyder Lee *
404b8e659SRyder Lee * Author: Roy Luo <royluo@google.com>
504b8e659SRyder Lee * Ryder Lee <ryder.lee@mediatek.com>
604b8e659SRyder Lee */
704b8e659SRyder Lee
804b8e659SRyder Lee #include <linux/firmware.h>
904b8e659SRyder Lee #include "mt7615.h"
1004b8e659SRyder Lee #include "mcu.h"
1104b8e659SRyder Lee #include "mac.h"
1204b8e659SRyder Lee #include "eeprom.h"
1304b8e659SRyder Lee
14f2dc8ea1SLorenzo Bianconi static bool prefer_offload_fw = true;
15f2dc8ea1SLorenzo Bianconi module_param(prefer_offload_fw, bool, 0644);
16f2dc8ea1SLorenzo Bianconi MODULE_PARM_DESC(prefer_offload_fw,
17f2dc8ea1SLorenzo Bianconi "Prefer client mode offload firmware (MT7663)");
18f2dc8ea1SLorenzo Bianconi
1904b8e659SRyder Lee struct mt7615_patch_hdr {
2004b8e659SRyder Lee char build_date[16];
2104b8e659SRyder Lee char platform[4];
2204b8e659SRyder Lee __be32 hw_sw_ver;
2304b8e659SRyder Lee __be32 patch_ver;
2404b8e659SRyder Lee __be16 checksum;
2504b8e659SRyder Lee } __packed;
2604b8e659SRyder Lee
2704b8e659SRyder Lee struct mt7615_fw_trailer {
2804b8e659SRyder Lee __le32 addr;
2904b8e659SRyder Lee u8 chip_id;
3004b8e659SRyder Lee u8 feature_set;
3104b8e659SRyder Lee u8 eco_code;
3204b8e659SRyder Lee char fw_ver[10];
3304b8e659SRyder Lee char build_date[15];
3404b8e659SRyder Lee __le32 len;
3504b8e659SRyder Lee } __packed;
3604b8e659SRyder Lee
37f40ac0f3SLorenzo Bianconi #define FW_V3_COMMON_TAILER_SIZE 36
38f40ac0f3SLorenzo Bianconi #define FW_V3_REGION_TAILER_SIZE 40
39f40ac0f3SLorenzo Bianconi #define FW_START_OVERRIDE BIT(0)
40f40ac0f3SLorenzo Bianconi #define FW_START_DLYCAL BIT(1)
41f40ac0f3SLorenzo Bianconi #define FW_START_WORKING_PDA_CR4 BIT(2)
42f40ac0f3SLorenzo Bianconi
43f40ac0f3SLorenzo Bianconi struct mt7663_fw_buf {
4454178cc1SLorenzo Bianconi __le32 crc;
4554178cc1SLorenzo Bianconi __le32 d_img_size;
4654178cc1SLorenzo Bianconi __le32 block_size;
47f40ac0f3SLorenzo Bianconi u8 rsv[4];
4854178cc1SLorenzo Bianconi __le32 img_dest_addr;
4954178cc1SLorenzo Bianconi __le32 img_size;
50f40ac0f3SLorenzo Bianconi u8 feature_set;
51f40ac0f3SLorenzo Bianconi };
52f40ac0f3SLorenzo Bianconi
5335da599fSFelix Fietkau #define MT7615_PATCH_ADDRESS 0x80000
5435da599fSFelix Fietkau #define MT7622_PATCH_ADDRESS 0x9c000
55f40ac0f3SLorenzo Bianconi #define MT7663_PATCH_ADDRESS 0xdc000
5604b8e659SRyder Lee
5704b8e659SRyder Lee #define N9_REGION_NUM 2
5804b8e659SRyder Lee #define CR4_REGION_NUM 1
5904b8e659SRyder Lee
6004b8e659SRyder Lee #define IMG_CRC_LEN 4
6104b8e659SRyder Lee
mt7615_mcu_fill_msg(struct mt7615_dev * dev,struct sk_buff * skb,int cmd,int * wait_seq)6263f09b6bSLorenzo Bianconi void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
6333d9ed72SLorenzo Bianconi int cmd, int *wait_seq)
6404b8e659SRyder Lee {
65e6d2070dSLorenzo Bianconi int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
66323d7daaSLorenzo Bianconi struct mt7615_uni_txd *uni_txd;
6704b8e659SRyder Lee struct mt7615_mcu_txd *mcu_txd;
6804b8e659SRyder Lee u8 seq, q_idx, pkt_fmt;
6904b8e659SRyder Lee __le32 *txd;
7063f09b6bSLorenzo Bianconi u32 val;
7104b8e659SRyder Lee
72e452c6ebSFelix Fietkau /* TODO: make dynamic based on msg type */
73e452c6ebSFelix Fietkau dev->mt76.mcu.timeout = 20 * HZ;
74e452c6ebSFelix Fietkau
7509872957SLorenzo Bianconi seq = ++dev->mt76.mcu.msg_seq & 0xf;
7604b8e659SRyder Lee if (!seq)
7709872957SLorenzo Bianconi seq = ++dev->mt76.mcu.msg_seq & 0xf;
78323d7daaSLorenzo Bianconi if (wait_seq)
79323d7daaSLorenzo Bianconi *wait_seq = seq;
8004b8e659SRyder Lee
8154722402SLorenzo Bianconi txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
82323d7daaSLorenzo Bianconi txd = (__le32 *)skb_push(skb, txd_len);
8304b8e659SRyder Lee
84ffc2198dSLorenzo Bianconi if (cmd != MCU_CMD(FW_SCATTER)) {
8504b8e659SRyder Lee q_idx = MT_TX_MCU_PORT_RX_Q0;
8604b8e659SRyder Lee pkt_fmt = MT_TX_TYPE_CMD;
8704b8e659SRyder Lee } else {
8804b8e659SRyder Lee q_idx = MT_TX_MCU_PORT_RX_FWDL;
8904b8e659SRyder Lee pkt_fmt = MT_TX_TYPE_FW;
9004b8e659SRyder Lee }
9104b8e659SRyder Lee
92132d8da5SLorenzo Bianconi val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
9304b8e659SRyder Lee FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
9404b8e659SRyder Lee FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
9504b8e659SRyder Lee txd[0] = cpu_to_le32(val);
9604b8e659SRyder Lee
9704b8e659SRyder Lee val = MT_TXD1_LONG_FORMAT |
9804b8e659SRyder Lee FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) |
9904b8e659SRyder Lee FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
10004b8e659SRyder Lee txd[1] = cpu_to_le32(val);
10104b8e659SRyder Lee
10254722402SLorenzo Bianconi if (cmd & __MCU_CMD_FIELD_UNI) {
103323d7daaSLorenzo Bianconi uni_txd = (struct mt7615_uni_txd *)txd;
104323d7daaSLorenzo Bianconi uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
105323d7daaSLorenzo Bianconi uni_txd->option = MCU_CMD_UNI_EXT_ACK;
106d14f0a5cSLorenzo Bianconi uni_txd->cid = cpu_to_le16(mcu_cmd);
107323d7daaSLorenzo Bianconi uni_txd->s2d_index = MCU_S2D_H2N;
108323d7daaSLorenzo Bianconi uni_txd->pkt_type = MCU_PKT_ID;
109323d7daaSLorenzo Bianconi uni_txd->seq = seq;
110323d7daaSLorenzo Bianconi
111323d7daaSLorenzo Bianconi return;
112323d7daaSLorenzo Bianconi }
113323d7daaSLorenzo Bianconi
114323d7daaSLorenzo Bianconi mcu_txd = (struct mt7615_mcu_txd *)txd;
115b28e22bdSFelix Fietkau mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
11604b8e659SRyder Lee mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
117323d7daaSLorenzo Bianconi mcu_txd->s2d_index = MCU_S2D_H2N;
11804b8e659SRyder Lee mcu_txd->pkt_type = MCU_PKT_ID;
11904b8e659SRyder Lee mcu_txd->seq = seq;
120e6d2070dSLorenzo Bianconi mcu_txd->cid = mcu_cmd;
121e6d2070dSLorenzo Bianconi mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);
12204b8e659SRyder Lee
123680a2eadSLorenzo Bianconi if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {
124e6d2070dSLorenzo Bianconi if (cmd & __MCU_CMD_FIELD_QUERY)
125e6d2070dSLorenzo Bianconi mcu_txd->set_query = MCU_Q_QUERY;
126e6d2070dSLorenzo Bianconi else
127e6d2070dSLorenzo Bianconi mcu_txd->set_query = MCU_Q_SET;
128e6d2070dSLorenzo Bianconi mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;
129e6d2070dSLorenzo Bianconi } else {
13027da3bfdSLorenzo Bianconi mcu_txd->set_query = MCU_Q_NA;
13104b8e659SRyder Lee }
13263f09b6bSLorenzo Bianconi }
133e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg);
13404b8e659SRyder Lee
mt7615_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)135f320d812SFelix Fietkau int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
1360e6a29e4SLorenzo Bianconi struct sk_buff *skb, int seq)
1370e6a29e4SLorenzo Bianconi {
13896a607b6SFelix Fietkau struct mt7615_mcu_rxd *rxd;
1390e6a29e4SLorenzo Bianconi int ret = 0;
1400e6a29e4SLorenzo Bianconi
14196a607b6SFelix Fietkau if (!skb) {
14253d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
14353d35b1aSLorenzo Bianconi cmd, seq);
14496a607b6SFelix Fietkau return -ETIMEDOUT;
14596a607b6SFelix Fietkau }
14696a607b6SFelix Fietkau
14796a607b6SFelix Fietkau rxd = (struct mt7615_mcu_rxd *)skb->data;
148f320d812SFelix Fietkau if (seq != rxd->seq)
149f320d812SFelix Fietkau return -EAGAIN;
1500e6a29e4SLorenzo Bianconi
151ffc2198dSLorenzo Bianconi if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
1520e6a29e4SLorenzo Bianconi skb_pull(skb, sizeof(*rxd) - 4);
1530e6a29e4SLorenzo Bianconi ret = *skb->data;
1549d8d136cSLorenzo Bianconi } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
1550e6a29e4SLorenzo Bianconi skb_pull(skb, sizeof(*rxd));
1560e6a29e4SLorenzo Bianconi ret = le32_to_cpu(*(__le32 *)skb->data);
157e6d2070dSLorenzo Bianconi } else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) {
158dc804058SFelix Fietkau skb_pull(skb, sizeof(*rxd));
159dc804058SFelix Fietkau ret = le32_to_cpu(*(__le32 *)&skb->data[8]);
16054722402SLorenzo Bianconi } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
16154722402SLorenzo Bianconi cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
16254722402SLorenzo Bianconi cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
16354722402SLorenzo Bianconi cmd == MCU_UNI_CMD(HIF_CTRL) ||
16454722402SLorenzo Bianconi cmd == MCU_UNI_CMD(OFFLOAD) ||
16554722402SLorenzo Bianconi cmd == MCU_UNI_CMD(SUSPEND)) {
16661d1f545SLorenzo Bianconi struct mt76_connac_mcu_uni_event *event;
167df5ab0d5SLorenzo Bianconi
168df5ab0d5SLorenzo Bianconi skb_pull(skb, sizeof(*rxd));
16961d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_uni_event *)skb->data;
170df5ab0d5SLorenzo Bianconi ret = le32_to_cpu(event->status);
171680a2eadSLorenzo Bianconi } else if (cmd == MCU_CE_QUERY(REG_READ)) {
17261d1f545SLorenzo Bianconi struct mt76_connac_mcu_reg_event *event;
173a66cbdd6SSean Wang
174a66cbdd6SSean Wang skb_pull(skb, sizeof(*rxd));
17561d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_reg_event *)skb->data;
176a66cbdd6SSean Wang ret = (int)le32_to_cpu(event->val);
1770e6a29e4SLorenzo Bianconi }
1780e6a29e4SLorenzo Bianconi
1790e6a29e4SLorenzo Bianconi return ret;
1800e6a29e4SLorenzo Bianconi }
181f320d812SFelix Fietkau EXPORT_SYMBOL_GPL(mt7615_mcu_parse_response);
1820e6a29e4SLorenzo Bianconi
1830e6a29e4SLorenzo Bianconi static int
mt7615_mcu_send_message(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * seq)184f4d45fe2SLorenzo Bianconi mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
185e452c6ebSFelix Fietkau int cmd, int *seq)
18604b8e659SRyder Lee {
187a3a2c2e7SLorenzo Bianconi struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
188b7c56875SNathan Chancellor enum mt76_mcuq_id qid;
18904b8e659SRyder Lee
190e452c6ebSFelix Fietkau mt7615_mcu_fill_msg(dev, skb, cmd, seq);
191e452c6ebSFelix Fietkau if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
192e637763bSLorenzo Bianconi qid = MT_MCUQ_WM;
193e452c6ebSFelix Fietkau else
194e637763bSLorenzo Bianconi qid = MT_MCUQ_FWDL;
19504b8e659SRyder Lee
196e637763bSLorenzo Bianconi return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0);
19704b8e659SRyder Lee }
19804b8e659SRyder Lee
mt7615_rf_rr(struct mt7615_dev * dev,u32 wf,u32 reg)199dc804058SFelix Fietkau u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
200dc804058SFelix Fietkau {
201dc804058SFelix Fietkau struct {
202dc804058SFelix Fietkau __le32 wifi_stream;
203dc804058SFelix Fietkau __le32 address;
204dc804058SFelix Fietkau __le32 data;
205dc804058SFelix Fietkau } req = {
206dc804058SFelix Fietkau .wifi_stream = cpu_to_le32(wf),
207dc804058SFelix Fietkau .address = cpu_to_le32(reg),
208dc804058SFelix Fietkau };
209dc804058SFelix Fietkau
210e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
211dc804058SFelix Fietkau &req, sizeof(req), true);
212dc804058SFelix Fietkau }
213dc804058SFelix Fietkau
mt7615_rf_wr(struct mt7615_dev * dev,u32 wf,u32 reg,u32 val)214dc804058SFelix Fietkau int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
215dc804058SFelix Fietkau {
216dc804058SFelix Fietkau struct {
217dc804058SFelix Fietkau __le32 wifi_stream;
218dc804058SFelix Fietkau __le32 address;
219dc804058SFelix Fietkau __le32 data;
220dc804058SFelix Fietkau } req = {
221dc804058SFelix Fietkau .wifi_stream = cpu_to_le32(wf),
222dc804058SFelix Fietkau .address = cpu_to_le32(reg),
223dc804058SFelix Fietkau .data = cpu_to_le32(val),
224dc804058SFelix Fietkau };
225dc804058SFelix Fietkau
226e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
227e6d2070dSLorenzo Bianconi &req, sizeof(req), false);
228dc804058SFelix Fietkau }
229dc804058SFelix Fietkau
mt7622_trigger_hif_int(struct mt7615_dev * dev,bool en)230ad2a1ea4SRyder Lee void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
231186b659cSLorenzo Bianconi {
232186b659cSLorenzo Bianconi if (!is_mt7622(&dev->mt76))
233186b659cSLorenzo Bianconi return;
234186b659cSLorenzo Bianconi
235186b659cSLorenzo Bianconi regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
236186b659cSLorenzo Bianconi MT_INFRACFG_MISC_AP2CONN_WAKE,
237186b659cSLorenzo Bianconi !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
238186b659cSLorenzo Bianconi }
2391cb7ea2aSFelix Fietkau EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);
240186b659cSLorenzo Bianconi
mt7615_mcu_drv_pmctrl(struct mt7615_dev * dev)241186b659cSLorenzo Bianconi static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
242186b659cSLorenzo Bianconi {
243186b659cSLorenzo Bianconi struct mt76_phy *mphy = &dev->mt76.phy;
244abe912aeSLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm;
245186b659cSLorenzo Bianconi struct mt76_dev *mdev = &dev->mt76;
2466892555dSLorenzo Bianconi u32 addr;
2476892555dSLorenzo Bianconi int err;
2486892555dSLorenzo Bianconi
2495c7d3744SFelix Fietkau if (is_mt7663(mdev)) {
2505c7d3744SFelix Fietkau /* Clear firmware own via N9 eint */
2515c7d3744SFelix Fietkau mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2525c7d3744SFelix Fietkau mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2535c7d3744SFelix Fietkau
2545c7d3744SFelix Fietkau addr = MT_CONN_HIF_ON_LPCTL;
2555c7d3744SFelix Fietkau } else {
2565c7d3744SFelix Fietkau addr = MT_CFG_LPCR_HOST;
2575c7d3744SFelix Fietkau }
2585c7d3744SFelix Fietkau
2596892555dSLorenzo Bianconi mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
2606892555dSLorenzo Bianconi
2616892555dSLorenzo Bianconi mt7622_trigger_hif_int(dev, true);
2626892555dSLorenzo Bianconi
2636892555dSLorenzo Bianconi err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
2646892555dSLorenzo Bianconi
2656892555dSLorenzo Bianconi mt7622_trigger_hif_int(dev, false);
2666892555dSLorenzo Bianconi
2676892555dSLorenzo Bianconi if (err) {
2686892555dSLorenzo Bianconi dev_err(mdev->dev, "driver own failed\n");
2696892555dSLorenzo Bianconi return -ETIMEDOUT;
2706892555dSLorenzo Bianconi }
2716892555dSLorenzo Bianconi
2726892555dSLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state);
2736892555dSLorenzo Bianconi
274abe912aeSLorenzo Bianconi pm->stats.last_wake_event = jiffies;
275abe912aeSLorenzo Bianconi pm->stats.doze_time += pm->stats.last_wake_event -
276abe912aeSLorenzo Bianconi pm->stats.last_doze_event;
277abe912aeSLorenzo Bianconi
2786892555dSLorenzo Bianconi return 0;
2796892555dSLorenzo Bianconi }
2806892555dSLorenzo Bianconi
mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev * dev)2816892555dSLorenzo Bianconi static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
2826892555dSLorenzo Bianconi {
2836892555dSLorenzo Bianconi struct mt76_phy *mphy = &dev->mt76.phy;
284abe912aeSLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm;
2857cd740f0SLorenzo Bianconi int i, err = 0;
286186b659cSLorenzo Bianconi
287abe912aeSLorenzo Bianconi mutex_lock(&pm->mutex);
2887cd740f0SLorenzo Bianconi
2897cd740f0SLorenzo Bianconi if (!test_bit(MT76_STATE_PM, &mphy->state))
290186b659cSLorenzo Bianconi goto out;
291186b659cSLorenzo Bianconi
292186b659cSLorenzo Bianconi for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
2936892555dSLorenzo Bianconi mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
2946892555dSLorenzo Bianconi if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
2956892555dSLorenzo Bianconi MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
296186b659cSLorenzo Bianconi break;
297186b659cSLorenzo Bianconi }
298186b659cSLorenzo Bianconi
299186b659cSLorenzo Bianconi if (i == MT7615_DRV_OWN_RETRY_COUNT) {
3006892555dSLorenzo Bianconi dev_err(dev->mt76.dev, "driver own failed\n");
3017cd740f0SLorenzo Bianconi err = -EIO;
3027cd740f0SLorenzo Bianconi goto out;
303186b659cSLorenzo Bianconi }
3047cd740f0SLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state);
305186b659cSLorenzo Bianconi
306abe912aeSLorenzo Bianconi pm->stats.last_wake_event = jiffies;
307abe912aeSLorenzo Bianconi pm->stats.doze_time += pm->stats.last_wake_event -
308abe912aeSLorenzo Bianconi pm->stats.last_doze_event;
309186b659cSLorenzo Bianconi out:
310abe912aeSLorenzo Bianconi mutex_unlock(&pm->mutex);
311186b659cSLorenzo Bianconi
3127cd740f0SLorenzo Bianconi return err;
313186b659cSLorenzo Bianconi }
314186b659cSLorenzo Bianconi
mt7615_mcu_fw_pmctrl(struct mt7615_dev * dev)315186b659cSLorenzo Bianconi static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
316186b659cSLorenzo Bianconi {
317186b659cSLorenzo Bianconi struct mt76_phy *mphy = &dev->mt76.phy;
318abe912aeSLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm;
319186b659cSLorenzo Bianconi int err = 0;
320186b659cSLorenzo Bianconi u32 addr;
321186b659cSLorenzo Bianconi
322abe912aeSLorenzo Bianconi mutex_lock(&pm->mutex);
3237cd740f0SLorenzo Bianconi
324abe912aeSLorenzo Bianconi if (mt76_connac_skip_fw_pmctrl(mphy, pm))
3257cd740f0SLorenzo Bianconi goto out;
326186b659cSLorenzo Bianconi
327186b659cSLorenzo Bianconi mt7622_trigger_hif_int(dev, true);
328186b659cSLorenzo Bianconi
329186b659cSLorenzo Bianconi addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
330186b659cSLorenzo Bianconi mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
331186b659cSLorenzo Bianconi
332186b659cSLorenzo Bianconi if (is_mt7622(&dev->mt76) &&
333186b659cSLorenzo Bianconi !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
3346892555dSLorenzo Bianconi MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
335186b659cSLorenzo Bianconi dev_err(dev->mt76.dev, "Timeout for firmware own\n");
336186b659cSLorenzo Bianconi clear_bit(MT76_STATE_PM, &mphy->state);
337186b659cSLorenzo Bianconi err = -EIO;
338186b659cSLorenzo Bianconi }
339186b659cSLorenzo Bianconi
340186b659cSLorenzo Bianconi mt7622_trigger_hif_int(dev, false);
34179717c4eSLorenzo Bianconi if (!err) {
342abe912aeSLorenzo Bianconi pm->stats.last_doze_event = jiffies;
343abe912aeSLorenzo Bianconi pm->stats.awake_time += pm->stats.last_doze_event -
344abe912aeSLorenzo Bianconi pm->stats.last_wake_event;
34579717c4eSLorenzo Bianconi }
3467cd740f0SLorenzo Bianconi out:
347abe912aeSLorenzo Bianconi mutex_unlock(&pm->mutex);
348186b659cSLorenzo Bianconi
349186b659cSLorenzo Bianconi return err;
350186b659cSLorenzo Bianconi }
351186b659cSLorenzo Bianconi
352d67a6646SLorenzo Bianconi static void
mt7615_mcu_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)3535ec87dc8SLorenzo Bianconi mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
3545ec87dc8SLorenzo Bianconi {
355d0a9123eSJohannes Berg if (vif->bss_conf.csa_active)
3565ec87dc8SLorenzo Bianconi ieee80211_csa_finish(vif);
3575ec87dc8SLorenzo Bianconi }
3585ec87dc8SLorenzo Bianconi
3595ec87dc8SLorenzo Bianconi static void
mt7615_mcu_rx_csa_notify(struct mt7615_dev * dev,struct sk_buff * skb)360402a695bSRyder Lee mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb)
361402a695bSRyder Lee {
362402a695bSRyder Lee struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
363402a695bSRyder Lee struct mt76_phy *mphy = &dev->mt76.phy;
364402a695bSRyder Lee struct mt7615_mcu_csa_notify *c;
365402a695bSRyder Lee
366402a695bSRyder Lee c = (struct mt7615_mcu_csa_notify *)skb->data;
367402a695bSRyder Lee
3683253f8fdSRyder Lee if (c->omac_idx > EXT_BSSID_MAX)
3693253f8fdSRyder Lee return;
3703253f8fdSRyder Lee
371402a695bSRyder Lee if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx))
372dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
373402a695bSRyder Lee
374402a695bSRyder Lee ieee80211_iterate_active_interfaces_atomic(mphy->hw,
375402a695bSRyder Lee IEEE80211_IFACE_ITER_RESUME_ALL,
376402a695bSRyder Lee mt7615_mcu_csa_finish, mphy->hw);
377402a695bSRyder Lee }
378402a695bSRyder Lee
379402a695bSRyder Lee static void
mt7615_mcu_rx_radar_detected(struct mt7615_dev * dev,struct sk_buff * skb)3805dabdf71SFelix Fietkau mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
3815dabdf71SFelix Fietkau {
3825dabdf71SFelix Fietkau struct mt76_phy *mphy = &dev->mt76.phy;
3835dabdf71SFelix Fietkau struct mt7615_mcu_rdd_report *r;
3845dabdf71SFelix Fietkau
3855dabdf71SFelix Fietkau r = (struct mt7615_mcu_rdd_report *)skb->data;
3865dabdf71SFelix Fietkau
387e3343d0fSRyder Lee if (!dev->radar_pattern.n_pulses && !r->long_detected &&
388e3343d0fSRyder Lee !r->constant_prf_detected && !r->staggered_prf_detected)
389e3343d0fSRyder Lee return;
390e3343d0fSRyder Lee
391dc44c45cSLorenzo Bianconi if (r->band_idx && dev->mt76.phys[MT_BAND1])
392dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
3935dabdf71SFelix Fietkau
394aac86cebSFelix Fietkau if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC)
395aac86cebSFelix Fietkau return;
396aac86cebSFelix Fietkau
3975dabdf71SFelix Fietkau ieee80211_radar_detected(mphy->hw);
3985dabdf71SFelix Fietkau dev->hw_pattern++;
3995dabdf71SFelix Fietkau }
4005dabdf71SFelix Fietkau
4015dabdf71SFelix Fietkau static void
mt7615_mcu_rx_log_message(struct mt7615_dev * dev,struct sk_buff * skb)402f347f81aSFelix Fietkau mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)
403f347f81aSFelix Fietkau {
404f347f81aSFelix Fietkau struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
405f347f81aSFelix Fietkau const char *data = (char *)&rxd[1];
406f347f81aSFelix Fietkau const char *type;
407f347f81aSFelix Fietkau
408f347f81aSFelix Fietkau switch (rxd->s2d_index) {
409f347f81aSFelix Fietkau case 0:
410f347f81aSFelix Fietkau type = "N9";
411f347f81aSFelix Fietkau break;
412f347f81aSFelix Fietkau case 2:
413f347f81aSFelix Fietkau type = "CR4";
414f347f81aSFelix Fietkau break;
415f347f81aSFelix Fietkau default:
416f347f81aSFelix Fietkau type = "unknown";
417f347f81aSFelix Fietkau break;
418f347f81aSFelix Fietkau }
419f347f81aSFelix Fietkau
420c8131dc3SDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
421d76d6c3bSFelix Fietkau (int)(skb->len - sizeof(*rxd)), data);
422f347f81aSFelix Fietkau }
423f347f81aSFelix Fietkau
424f347f81aSFelix Fietkau static void
mt7615_mcu_rx_ext_event(struct mt7615_dev * dev,struct sk_buff * skb)425d67a6646SLorenzo Bianconi mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
426d67a6646SLorenzo Bianconi {
427d67a6646SLorenzo Bianconi struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
428d67a6646SLorenzo Bianconi
429d67a6646SLorenzo Bianconi switch (rxd->ext_eid) {
430d67a6646SLorenzo Bianconi case MCU_EXT_EVENT_RDD_REPORT:
4315dabdf71SFelix Fietkau mt7615_mcu_rx_radar_detected(dev, skb);
432d67a6646SLorenzo Bianconi break;
4335ec87dc8SLorenzo Bianconi case MCU_EXT_EVENT_CSA_NOTIFY:
434402a695bSRyder Lee mt7615_mcu_rx_csa_notify(dev, skb);
4355ec87dc8SLorenzo Bianconi break;
436f347f81aSFelix Fietkau case MCU_EXT_EVENT_FW_LOG_2_HOST:
437f347f81aSFelix Fietkau mt7615_mcu_rx_log_message(dev, skb);
438f347f81aSFelix Fietkau break;
439d67a6646SLorenzo Bianconi default:
440d67a6646SLorenzo Bianconi break;
441d67a6646SLorenzo Bianconi }
442d67a6646SLorenzo Bianconi }
443d67a6646SLorenzo Bianconi
444d67a6646SLorenzo Bianconi static void
mt7615_mcu_scan_event(struct mt7615_dev * dev,struct sk_buff * skb)44520305f98SLorenzo Bianconi mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
446fcdfc29eSLorenzo Bianconi {
44720305f98SLorenzo Bianconi u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd);
448fcdfc29eSLorenzo Bianconi struct mt7615_phy *phy;
449fcdfc29eSLorenzo Bianconi struct mt76_phy *mphy;
450fcdfc29eSLorenzo Bianconi
451dc44c45cSLorenzo Bianconi if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1])
452dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
453fcdfc29eSLorenzo Bianconi else
454fcdfc29eSLorenzo Bianconi mphy = &dev->mt76.phy;
455fcdfc29eSLorenzo Bianconi
456fcdfc29eSLorenzo Bianconi phy = (struct mt7615_phy *)mphy->priv;
45720305f98SLorenzo Bianconi
45820305f98SLorenzo Bianconi spin_lock_bh(&dev->mt76.lock);
45920305f98SLorenzo Bianconi __skb_queue_tail(&phy->scan_event_list, skb);
46020305f98SLorenzo Bianconi spin_unlock_bh(&dev->mt76.lock);
46120305f98SLorenzo Bianconi
462fcdfc29eSLorenzo Bianconi ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
463fcdfc29eSLorenzo Bianconi MT7615_HW_SCAN_TIMEOUT);
464fcdfc29eSLorenzo Bianconi }
465fcdfc29eSLorenzo Bianconi
466fcdfc29eSLorenzo Bianconi static void
mt7615_mcu_roc_event(struct mt7615_dev * dev,struct sk_buff * skb)4677307f296SLorenzo Bianconi mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
4687307f296SLorenzo Bianconi {
4697307f296SLorenzo Bianconi struct mt7615_roc_tlv *event;
4707307f296SLorenzo Bianconi struct mt7615_phy *phy;
4717307f296SLorenzo Bianconi struct mt76_phy *mphy;
4727307f296SLorenzo Bianconi int duration;
4737307f296SLorenzo Bianconi
4747307f296SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
4757307f296SLorenzo Bianconi event = (struct mt7615_roc_tlv *)skb->data;
4767307f296SLorenzo Bianconi
477dc44c45cSLorenzo Bianconi if (event->dbdc_band && dev->mt76.phys[MT_BAND1])
478dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
4797307f296SLorenzo Bianconi else
4807307f296SLorenzo Bianconi mphy = &dev->mt76.phy;
4817307f296SLorenzo Bianconi
4827307f296SLorenzo Bianconi ieee80211_ready_on_channel(mphy->hw);
4837307f296SLorenzo Bianconi
4847307f296SLorenzo Bianconi phy = (struct mt7615_phy *)mphy->priv;
4857307f296SLorenzo Bianconi phy->roc_grant = true;
4867307f296SLorenzo Bianconi wake_up(&phy->roc_wait);
4877307f296SLorenzo Bianconi
4887307f296SLorenzo Bianconi duration = le32_to_cpu(event->max_interval);
4897307f296SLorenzo Bianconi mod_timer(&phy->roc_timer,
4907307f296SLorenzo Bianconi round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
4917307f296SLorenzo Bianconi }
4927307f296SLorenzo Bianconi
4937307f296SLorenzo Bianconi static void
mt7615_mcu_beacon_loss_event(struct mt7615_dev * dev,struct sk_buff * skb)49486c60179SLorenzo Bianconi mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb)
49586c60179SLorenzo Bianconi {
496d0e274afSLorenzo Bianconi struct mt76_connac_beacon_loss_event *event;
49786c60179SLorenzo Bianconi struct mt76_phy *mphy;
49886c60179SLorenzo Bianconi u8 band_idx = 0; /* DBDC support */
49986c60179SLorenzo Bianconi
50086c60179SLorenzo Bianconi skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
501d0e274afSLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data;
502dc44c45cSLorenzo Bianconi if (band_idx && dev->mt76.phys[MT_BAND1])
503dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
50486c60179SLorenzo Bianconi else
50586c60179SLorenzo Bianconi mphy = &dev->mt76.phy;
50686c60179SLorenzo Bianconi
50786c60179SLorenzo Bianconi ieee80211_iterate_active_interfaces_atomic(mphy->hw,
50886c60179SLorenzo Bianconi IEEE80211_IFACE_ITER_RESUME_ALL,
509d0e274afSLorenzo Bianconi mt76_connac_mcu_beacon_loss_iter,
510d0e274afSLorenzo Bianconi event);
51186c60179SLorenzo Bianconi }
51286c60179SLorenzo Bianconi
51386c60179SLorenzo Bianconi static void
mt7615_mcu_bss_event(struct mt7615_dev * dev,struct sk_buff * skb)514bb366c5bSSean Wang mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb)
515bb366c5bSSean Wang {
516d0e274afSLorenzo Bianconi struct mt76_connac_mcu_bss_event *event;
517bb366c5bSSean Wang struct mt76_phy *mphy;
518ffc54ee2SLorenzo Bianconi u8 band_idx = 0; /* DBDC support */
519bb366c5bSSean Wang
520d0e274afSLorenzo Bianconi skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
521d0e274afSLorenzo Bianconi event = (struct mt76_connac_mcu_bss_event *)skb->data;
522bb366c5bSSean Wang
523dc44c45cSLorenzo Bianconi if (band_idx && dev->mt76.phys[MT_BAND1])
524dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
525bb366c5bSSean Wang else
526bb366c5bSSean Wang mphy = &dev->mt76.phy;
527bb366c5bSSean Wang
528bb366c5bSSean Wang if (event->is_absent)
529bb366c5bSSean Wang ieee80211_stop_queues(mphy->hw);
530bb366c5bSSean Wang else
531bb366c5bSSean Wang ieee80211_wake_queues(mphy->hw);
532bb366c5bSSean Wang }
533bb366c5bSSean Wang
534bb366c5bSSean Wang static void
mt7615_mcu_rx_unsolicited_event(struct mt7615_dev * dev,struct sk_buff * skb)535d67a6646SLorenzo Bianconi mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
536d67a6646SLorenzo Bianconi {
537d67a6646SLorenzo Bianconi struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
538d67a6646SLorenzo Bianconi
539d67a6646SLorenzo Bianconi switch (rxd->eid) {
540d67a6646SLorenzo Bianconi case MCU_EVENT_EXT:
541d67a6646SLorenzo Bianconi mt7615_mcu_rx_ext_event(dev, skb);
542d67a6646SLorenzo Bianconi break;
54386c60179SLorenzo Bianconi case MCU_EVENT_BSS_BEACON_LOSS:
54486c60179SLorenzo Bianconi mt7615_mcu_beacon_loss_event(dev, skb);
54586c60179SLorenzo Bianconi break;
5467307f296SLorenzo Bianconi case MCU_EVENT_ROC:
5477307f296SLorenzo Bianconi mt7615_mcu_roc_event(dev, skb);
5487307f296SLorenzo Bianconi break;
54920305f98SLorenzo Bianconi case MCU_EVENT_SCHED_SCAN_DONE:
550fcdfc29eSLorenzo Bianconi case MCU_EVENT_SCAN_DONE:
55120305f98SLorenzo Bianconi mt7615_mcu_scan_event(dev, skb);
55220305f98SLorenzo Bianconi return;
553bb366c5bSSean Wang case MCU_EVENT_BSS_ABSENCE:
554bb366c5bSSean Wang mt7615_mcu_bss_event(dev, skb);
555bb366c5bSSean Wang break;
556d2bf7959SLorenzo Bianconi case MCU_EVENT_COREDUMP:
557d2bf7959SLorenzo Bianconi mt76_connac_mcu_coredump_event(&dev->mt76, skb,
558d2bf7959SLorenzo Bianconi &dev->coredump);
559d2bf7959SLorenzo Bianconi return;
560d67a6646SLorenzo Bianconi default:
561d67a6646SLorenzo Bianconi break;
562d67a6646SLorenzo Bianconi }
563d67a6646SLorenzo Bianconi dev_kfree_skb(skb);
564d67a6646SLorenzo Bianconi }
565d67a6646SLorenzo Bianconi
mt7615_mcu_rx_event(struct mt7615_dev * dev,struct sk_buff * skb)566d67a6646SLorenzo Bianconi void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
567d67a6646SLorenzo Bianconi {
568d67a6646SLorenzo Bianconi struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
569d67a6646SLorenzo Bianconi
570d67a6646SLorenzo Bianconi if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
571d67a6646SLorenzo Bianconi rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
572d67a6646SLorenzo Bianconi rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
573d67a6646SLorenzo Bianconi rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
57486c60179SLorenzo Bianconi rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
57520305f98SLorenzo Bianconi rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
576bb366c5bSSean Wang rxd->eid == MCU_EVENT_BSS_ABSENCE ||
577fcdfc29eSLorenzo Bianconi rxd->eid == MCU_EVENT_SCAN_DONE ||
578d2bf7959SLorenzo Bianconi rxd->eid == MCU_EVENT_COREDUMP ||
5797307f296SLorenzo Bianconi rxd->eid == MCU_EVENT_ROC ||
580d67a6646SLorenzo Bianconi !rxd->seq)
581d67a6646SLorenzo Bianconi mt7615_mcu_rx_unsolicited_event(dev, skb);
582d67a6646SLorenzo Bianconi else
583d67a6646SLorenzo Bianconi mt76_mcu_rx_event(&dev->mt76, skb);
584d67a6646SLorenzo Bianconi }
585d67a6646SLorenzo Bianconi
586062c3699SLorenzo Bianconi static int
mt7615_mcu_muar_config(struct mt7615_dev * dev,struct ieee80211_vif * vif,bool bssid,bool enable)587d8d59f66SRyder Lee mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif,
588d8d59f66SRyder Lee bool bssid, bool enable)
589d8d59f66SRyder Lee {
590d8d59f66SRyder Lee struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
59185d96704SLorenzo Bianconi u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
592d8d59f66SRyder Lee u32 mask = dev->omac_mask >> 32 & ~BIT(idx);
593d8d59f66SRyder Lee const u8 *addr = vif->addr;
594d8d59f66SRyder Lee struct {
595d8d59f66SRyder Lee u8 mode;
596d8d59f66SRyder Lee u8 force_clear;
597d8d59f66SRyder Lee u8 clear_bitmap[8];
598d8d59f66SRyder Lee u8 entry_count;
599d8d59f66SRyder Lee u8 write;
600d8d59f66SRyder Lee
601d8d59f66SRyder Lee u8 index;
602d8d59f66SRyder Lee u8 bssid;
603d8d59f66SRyder Lee u8 addr[ETH_ALEN];
604d8d59f66SRyder Lee } __packed req = {
605d8d59f66SRyder Lee .mode = !!mask || enable,
606d8d59f66SRyder Lee .entry_count = 1,
607d8d59f66SRyder Lee .write = 1,
608d8d59f66SRyder Lee
609d8d59f66SRyder Lee .index = idx * 2 + bssid,
610d8d59f66SRyder Lee };
611d8d59f66SRyder Lee
612d8d59f66SRyder Lee if (bssid)
613d8d59f66SRyder Lee addr = vif->bss_conf.bssid;
614d8d59f66SRyder Lee
615d8d59f66SRyder Lee if (enable)
616d8d59f66SRyder Lee ether_addr_copy(req.addr, addr);
617d8d59f66SRyder Lee
618e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE),
619e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
620d8d59f66SRyder Lee }
621d8d59f66SRyder Lee
622d8d59f66SRyder Lee static int
mt7615_mcu_add_dev(struct mt7615_phy * phy,struct ieee80211_vif * vif,bool enable)623d0e274afSLorenzo Bianconi mt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
624062c3699SLorenzo Bianconi bool enable)
625062c3699SLorenzo Bianconi {
626062c3699SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
627d0e274afSLorenzo Bianconi struct mt7615_dev *dev = phy->dev;
628062c3699SLorenzo Bianconi struct {
629062c3699SLorenzo Bianconi struct req_hdr {
630062c3699SLorenzo Bianconi u8 omac_idx;
631062c3699SLorenzo Bianconi u8 band_idx;
632062c3699SLorenzo Bianconi __le16 tlv_num;
633062c3699SLorenzo Bianconi u8 is_tlv_append;
634062c3699SLorenzo Bianconi u8 rsv[3];
635062c3699SLorenzo Bianconi } __packed hdr;
636062c3699SLorenzo Bianconi struct req_tlv {
637062c3699SLorenzo Bianconi __le16 tag;
638062c3699SLorenzo Bianconi __le16 len;
639062c3699SLorenzo Bianconi u8 active;
640062c3699SLorenzo Bianconi u8 band_idx;
641062c3699SLorenzo Bianconi u8 omac_addr[ETH_ALEN];
642062c3699SLorenzo Bianconi } __packed tlv;
643062c3699SLorenzo Bianconi } data = {
644062c3699SLorenzo Bianconi .hdr = {
64585d96704SLorenzo Bianconi .omac_idx = mvif->mt76.omac_idx,
64685d96704SLorenzo Bianconi .band_idx = mvif->mt76.band_idx,
647062c3699SLorenzo Bianconi .tlv_num = cpu_to_le16(1),
648062c3699SLorenzo Bianconi .is_tlv_append = 1,
649062c3699SLorenzo Bianconi },
650062c3699SLorenzo Bianconi .tlv = {
651062c3699SLorenzo Bianconi .tag = cpu_to_le16(DEV_INFO_ACTIVE),
652062c3699SLorenzo Bianconi .len = cpu_to_le16(sizeof(struct req_tlv)),
653062c3699SLorenzo Bianconi .active = enable,
65485d96704SLorenzo Bianconi .band_idx = mvif->mt76.band_idx,
655062c3699SLorenzo Bianconi },
656062c3699SLorenzo Bianconi };
657062c3699SLorenzo Bianconi
65885d96704SLorenzo Bianconi if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
659d8d59f66SRyder Lee return mt7615_mcu_muar_config(dev, vif, false, enable);
660d8d59f66SRyder Lee
661062c3699SLorenzo Bianconi memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
662e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
663062c3699SLorenzo Bianconi &data, sizeof(data), true);
664062c3699SLorenzo Bianconi }
665062c3699SLorenzo Bianconi
666062c3699SLorenzo Bianconi static int
mt7615_mcu_add_beacon_offload(struct mt7615_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)667062c3699SLorenzo Bianconi mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
668062c3699SLorenzo Bianconi struct ieee80211_hw *hw,
669062c3699SLorenzo Bianconi struct ieee80211_vif *vif, bool enable)
670062c3699SLorenzo Bianconi {
671062c3699SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
672062c3699SLorenzo Bianconi struct mt76_wcid *wcid = &dev->mt76.global_wcid;
673062c3699SLorenzo Bianconi struct ieee80211_mutable_offsets offs;
674062c3699SLorenzo Bianconi struct ieee80211_tx_info *info;
675062c3699SLorenzo Bianconi struct req {
676062c3699SLorenzo Bianconi u8 omac_idx;
677062c3699SLorenzo Bianconi u8 enable;
678062c3699SLorenzo Bianconi u8 wlan_idx;
679062c3699SLorenzo Bianconi u8 band_idx;
680062c3699SLorenzo Bianconi u8 pkt_type;
681062c3699SLorenzo Bianconi u8 need_pre_tbtt_int;
682062c3699SLorenzo Bianconi __le16 csa_ie_pos;
683062c3699SLorenzo Bianconi __le16 pkt_len;
684062c3699SLorenzo Bianconi __le16 tim_ie_pos;
685062c3699SLorenzo Bianconi u8 pkt[512];
686062c3699SLorenzo Bianconi u8 csa_cnt;
687062c3699SLorenzo Bianconi /* bss color change */
688062c3699SLorenzo Bianconi u8 bcc_cnt;
689062c3699SLorenzo Bianconi __le16 bcc_ie_pos;
690062c3699SLorenzo Bianconi } __packed req = {
69185d96704SLorenzo Bianconi .omac_idx = mvif->mt76.omac_idx,
692062c3699SLorenzo Bianconi .enable = enable,
693062c3699SLorenzo Bianconi .wlan_idx = wcid->idx,
69485d96704SLorenzo Bianconi .band_idx = mvif->mt76.band_idx,
695062c3699SLorenzo Bianconi };
696062c3699SLorenzo Bianconi struct sk_buff *skb;
697062c3699SLorenzo Bianconi
6988a5a5dbfSRyder Lee if (!enable)
6998a5a5dbfSRyder Lee goto out;
7008a5a5dbfSRyder Lee
7016e8912a5SShaul Triebitz skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
702062c3699SLorenzo Bianconi if (!skb)
703062c3699SLorenzo Bianconi return -EINVAL;
704062c3699SLorenzo Bianconi
705062c3699SLorenzo Bianconi if (skb->len > 512 - MT_TXD_SIZE) {
706062c3699SLorenzo Bianconi dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
707062c3699SLorenzo Bianconi dev_kfree_skb(skb);
708062c3699SLorenzo Bianconi return -EINVAL;
709062c3699SLorenzo Bianconi }
710062c3699SLorenzo Bianconi
711062c3699SLorenzo Bianconi info = IEEE80211_SKB_CB(skb);
712a062f001SLorenzo Bianconi info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx);
713062c3699SLorenzo Bianconi
714062c3699SLorenzo Bianconi mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
7151d5af0acSFelix Fietkau 0, NULL, 0, true);
716062c3699SLorenzo Bianconi memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
717062c3699SLorenzo Bianconi req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
718062c3699SLorenzo Bianconi req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
7198552a434SJohn Crispin if (offs.cntdwn_counter_offs[0]) {
720062c3699SLorenzo Bianconi u16 csa_offs;
721062c3699SLorenzo Bianconi
7228552a434SJohn Crispin csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
723062c3699SLorenzo Bianconi req.csa_ie_pos = cpu_to_le16(csa_offs);
7248552a434SJohn Crispin req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]];
725062c3699SLorenzo Bianconi }
726062c3699SLorenzo Bianconi dev_kfree_skb(skb);
727062c3699SLorenzo Bianconi
7288a5a5dbfSRyder Lee out:
729e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(BCN_OFFLOAD), &req,
730cb5cdd4cSFelix Fietkau sizeof(req), true);
731062c3699SLorenzo Bianconi }
732062c3699SLorenzo Bianconi
733062c3699SLorenzo Bianconi static int
mt7615_mcu_ctrl_pm_state(struct mt7615_dev * dev,int band,int state)734062c3699SLorenzo Bianconi mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
735062c3699SLorenzo Bianconi {
73648d743d1SLorenzo Bianconi return mt76_connac_mcu_set_pm(&dev->mt76, band, state);
737062c3699SLorenzo Bianconi }
738062c3699SLorenzo Bianconi
739adb2ed0eSLorenzo Bianconi static int
mt7615_mcu_add_bss(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)7405d3a4a4bSLorenzo Bianconi mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
741f5596850SLorenzo Bianconi struct ieee80211_sta *sta, bool enable)
742062c3699SLorenzo Bianconi {
743062c3699SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
7445d3a4a4bSLorenzo Bianconi struct mt7615_dev *dev = phy->dev;
745062c3699SLorenzo Bianconi struct sk_buff *skb;
746062c3699SLorenzo Bianconi
74785d96704SLorenzo Bianconi if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
748d8d59f66SRyder Lee mt7615_mcu_muar_config(dev, vif, true, enable);
749d8d59f66SRyder Lee
750d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL);
751062c3699SLorenzo Bianconi if (IS_ERR(skb))
752062c3699SLorenzo Bianconi return PTR_ERR(skb);
753062c3699SLorenzo Bianconi
754062c3699SLorenzo Bianconi if (enable)
75554735e11SLorenzo Bianconi mt76_connac_mcu_bss_omac_tlv(skb, vif);
756062c3699SLorenzo Bianconi
75749126ac1SLorenzo Bianconi mt76_connac_mcu_bss_basic_tlv(skb, vif, sta, phy->mt76,
75849126ac1SLorenzo Bianconi mvif->sta.wcid.idx, enable);
759062c3699SLorenzo Bianconi
76085d96704SLorenzo Bianconi if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
76185d96704SLorenzo Bianconi mvif->mt76.omac_idx < REPEATER_BSSID_START)
76264f4e823SLorenzo Bianconi mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
763062c3699SLorenzo Bianconi
764fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
765e6d2070dSLorenzo Bianconi MCU_EXT_CMD(BSS_INFO_UPDATE), true);
766062c3699SLorenzo Bianconi }
767062c3699SLorenzo Bianconi
768062c3699SLorenzo Bianconi static int
mt7615_mcu_wtbl_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)7696f4d7cc8SLorenzo Bianconi mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
7706f4d7cc8SLorenzo Bianconi struct ieee80211_ampdu_params *params,
7716f4d7cc8SLorenzo Bianconi bool enable)
7726f4d7cc8SLorenzo Bianconi {
7736f4d7cc8SLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
7746f4d7cc8SLorenzo Bianconi struct mt7615_vif *mvif = msta->vif;
7756f4d7cc8SLorenzo Bianconi struct wtbl_req_hdr *wtbl_hdr;
7766f4d7cc8SLorenzo Bianconi struct sk_buff *skb = NULL;
7776f4d7cc8SLorenzo Bianconi int err;
7786f4d7cc8SLorenzo Bianconi
779d0e274afSLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
780d0e274afSLorenzo Bianconi WTBL_SET, NULL, &skb);
7816f4d7cc8SLorenzo Bianconi if (IS_ERR(wtbl_hdr))
7826f4d7cc8SLorenzo Bianconi return PTR_ERR(wtbl_hdr);
7836f4d7cc8SLorenzo Bianconi
784d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true,
785d0e274afSLorenzo Bianconi NULL, wtbl_hdr);
7866f4d7cc8SLorenzo Bianconi
787e6d2070dSLorenzo Bianconi err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
788e6d2070dSLorenzo Bianconi MCU_EXT_CMD(WTBL_UPDATE), true);
7896f4d7cc8SLorenzo Bianconi if (err < 0)
7906f4d7cc8SLorenzo Bianconi return err;
7916f4d7cc8SLorenzo Bianconi
792d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
793d0e274afSLorenzo Bianconi &msta->wcid);
7946f4d7cc8SLorenzo Bianconi if (IS_ERR(skb))
7956f4d7cc8SLorenzo Bianconi return PTR_ERR(skb);
7966f4d7cc8SLorenzo Bianconi
797d0e274afSLorenzo Bianconi mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true);
7986f4d7cc8SLorenzo Bianconi
799fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
800e6d2070dSLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE), true);
8016f4d7cc8SLorenzo Bianconi }
8026f4d7cc8SLorenzo Bianconi
8036f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_wtbl_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)8046f4d7cc8SLorenzo Bianconi mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
8056f4d7cc8SLorenzo Bianconi struct ieee80211_ampdu_params *params,
8066f4d7cc8SLorenzo Bianconi bool enable)
8076f4d7cc8SLorenzo Bianconi {
8086f4d7cc8SLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
8096f4d7cc8SLorenzo Bianconi struct mt7615_vif *mvif = msta->vif;
8106f4d7cc8SLorenzo Bianconi struct wtbl_req_hdr *wtbl_hdr;
8116f4d7cc8SLorenzo Bianconi struct sk_buff *skb;
8126f4d7cc8SLorenzo Bianconi int err;
8136f4d7cc8SLorenzo Bianconi
814d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
815d0e274afSLorenzo Bianconi &msta->wcid);
8166f4d7cc8SLorenzo Bianconi if (IS_ERR(skb))
8176f4d7cc8SLorenzo Bianconi return PTR_ERR(skb);
8186f4d7cc8SLorenzo Bianconi
819d0e274afSLorenzo Bianconi mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
8206f4d7cc8SLorenzo Bianconi
821fa62d0e0SFelix Fietkau err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
822e6d2070dSLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE), true);
8236f4d7cc8SLorenzo Bianconi if (err < 0 || !enable)
8246f4d7cc8SLorenzo Bianconi return err;
8256f4d7cc8SLorenzo Bianconi
8266f4d7cc8SLorenzo Bianconi skb = NULL;
827d0e274afSLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
828d0e274afSLorenzo Bianconi WTBL_SET, NULL, &skb);
8296f4d7cc8SLorenzo Bianconi if (IS_ERR(wtbl_hdr))
8306f4d7cc8SLorenzo Bianconi return PTR_ERR(wtbl_hdr);
8316f4d7cc8SLorenzo Bianconi
832d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
833d0e274afSLorenzo Bianconi NULL, wtbl_hdr);
8346f4d7cc8SLorenzo Bianconi
835e6d2070dSLorenzo Bianconi return mt76_mcu_skb_send_msg(&dev->mt76, skb,
836e6d2070dSLorenzo Bianconi MCU_EXT_CMD(WTBL_UPDATE), true);
8376f4d7cc8SLorenzo Bianconi }
8386f4d7cc8SLorenzo Bianconi
83999c457d9SLorenzo Bianconi static int
mt7615_mcu_wtbl_sta_add(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)840d0e274afSLorenzo Bianconi mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
84199c457d9SLorenzo Bianconi struct ieee80211_sta *sta, bool enable)
84299c457d9SLorenzo Bianconi {
84399c457d9SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
84499c457d9SLorenzo Bianconi struct sk_buff *skb, *sskb, *wskb = NULL;
845d0e274afSLorenzo Bianconi struct mt7615_dev *dev = phy->dev;
84699c457d9SLorenzo Bianconi struct wtbl_req_hdr *wtbl_hdr;
847b4985ff1SLorenzo Bianconi struct mt7615_sta *msta;
848df6b739fSFelix Fietkau bool new_entry = true;
84999c457d9SLorenzo Bianconi int cmd, err;
85099c457d9SLorenzo Bianconi
851b4985ff1SLorenzo Bianconi msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
852b4985ff1SLorenzo Bianconi
853d0e274afSLorenzo Bianconi sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
854d0e274afSLorenzo Bianconi &msta->wcid);
85599c457d9SLorenzo Bianconi if (IS_ERR(sskb))
85699c457d9SLorenzo Bianconi return PTR_ERR(sskb);
85799c457d9SLorenzo Bianconi
858df6b739fSFelix Fietkau if (!sta) {
859df6b739fSFelix Fietkau if (mvif->sta_added)
860df6b739fSFelix Fietkau new_entry = false;
861df6b739fSFelix Fietkau else
862df6b739fSFelix Fietkau mvif->sta_added = true;
863df6b739fSFelix Fietkau }
8641b83d17cSSean Wang mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
8651b83d17cSSean Wang new_entry);
866d0e274afSLorenzo Bianconi if (enable && sta)
867f5056657SSean Wang mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
868f5056657SSean Wang MT76_STA_INFO_STATE_ASSOC);
86999c457d9SLorenzo Bianconi
870d0e274afSLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
871d0e274afSLorenzo Bianconi WTBL_RESET_AND_SET, NULL,
872d0e274afSLorenzo Bianconi &wskb);
87399c457d9SLorenzo Bianconi if (IS_ERR(wtbl_hdr))
87499c457d9SLorenzo Bianconi return PTR_ERR(wtbl_hdr);
87599c457d9SLorenzo Bianconi
876b4985ff1SLorenzo Bianconi if (enable) {
877d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta,
878d0e274afSLorenzo Bianconi NULL, wtbl_hdr);
879b4985ff1SLorenzo Bianconi if (sta)
880d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,
881499da720SMeiChia Chiu NULL, wtbl_hdr, true, true);
882868fe07eSLorenzo Bianconi mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid,
883868fe07eSLorenzo Bianconi NULL, wtbl_hdr);
884b4985ff1SLorenzo Bianconi }
88599c457d9SLorenzo Bianconi
886e6d2070dSLorenzo Bianconi cmd = enable ? MCU_EXT_CMD(WTBL_UPDATE) : MCU_EXT_CMD(STA_REC_UPDATE);
88799c457d9SLorenzo Bianconi skb = enable ? wskb : sskb;
88899c457d9SLorenzo Bianconi
889fa62d0e0SFelix Fietkau err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
8902bccc841SLorenzo Bianconi if (err < 0) {
8912bccc841SLorenzo Bianconi skb = enable ? sskb : wskb;
8922bccc841SLorenzo Bianconi dev_kfree_skb(skb);
8932bccc841SLorenzo Bianconi
89499c457d9SLorenzo Bianconi return err;
8952bccc841SLorenzo Bianconi }
89699c457d9SLorenzo Bianconi
897e6d2070dSLorenzo Bianconi cmd = enable ? MCU_EXT_CMD(STA_REC_UPDATE) : MCU_EXT_CMD(WTBL_UPDATE);
89899c457d9SLorenzo Bianconi skb = enable ? sskb : wskb;
89999c457d9SLorenzo Bianconi
900fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
90199c457d9SLorenzo Bianconi }
90299c457d9SLorenzo Bianconi
90354c31b9eSLorenzo Bianconi static int
mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)90454c31b9eSLorenzo Bianconi mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev,
90554c31b9eSLorenzo Bianconi struct ieee80211_vif *vif,
90654c31b9eSLorenzo Bianconi struct ieee80211_sta *sta)
90754c31b9eSLorenzo Bianconi {
9085a521c0fSLorenzo Bianconi return mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
90954c31b9eSLorenzo Bianconi }
91054c31b9eSLorenzo Bianconi
9116f4d7cc8SLorenzo Bianconi static const struct mt7615_mcu_ops wtbl_update_ops = {
912062c3699SLorenzo Bianconi .add_beacon_offload = mt7615_mcu_add_beacon_offload,
913062c3699SLorenzo Bianconi .set_pm_state = mt7615_mcu_ctrl_pm_state,
914062c3699SLorenzo Bianconi .add_dev_info = mt7615_mcu_add_dev,
915062c3699SLorenzo Bianconi .add_bss_info = mt7615_mcu_add_bss,
9166f4d7cc8SLorenzo Bianconi .add_tx_ba = mt7615_mcu_wtbl_tx_ba,
9176f4d7cc8SLorenzo Bianconi .add_rx_ba = mt7615_mcu_wtbl_rx_ba,
91899c457d9SLorenzo Bianconi .sta_add = mt7615_mcu_wtbl_sta_add,
919186b659cSLorenzo Bianconi .set_drv_ctrl = mt7615_mcu_drv_pmctrl,
920186b659cSLorenzo Bianconi .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
92154c31b9eSLorenzo Bianconi .set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans,
9226f4d7cc8SLorenzo Bianconi };
9236f4d7cc8SLorenzo Bianconi
9246f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable,bool tx)9256f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_ba(struct mt7615_dev *dev,
9266f4d7cc8SLorenzo Bianconi struct ieee80211_ampdu_params *params,
9276f4d7cc8SLorenzo Bianconi bool enable, bool tx)
9286f4d7cc8SLorenzo Bianconi {
9296f4d7cc8SLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
9306f4d7cc8SLorenzo Bianconi struct mt7615_vif *mvif = msta->vif;
9316f4d7cc8SLorenzo Bianconi struct wtbl_req_hdr *wtbl_hdr;
9326f4d7cc8SLorenzo Bianconi struct tlv *sta_wtbl;
9336f4d7cc8SLorenzo Bianconi struct sk_buff *skb;
9346f4d7cc8SLorenzo Bianconi
935d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
936d0e274afSLorenzo Bianconi &msta->wcid);
9376f4d7cc8SLorenzo Bianconi if (IS_ERR(skb))
9386f4d7cc8SLorenzo Bianconi return PTR_ERR(skb);
9396f4d7cc8SLorenzo Bianconi
940d0e274afSLorenzo Bianconi mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
9418327cd82SLorenzo Bianconi
942d0e274afSLorenzo Bianconi sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
9436f4d7cc8SLorenzo Bianconi
944d0e274afSLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
945d0e274afSLorenzo Bianconi WTBL_SET, sta_wtbl, &skb);
946baa3afb3SLorenzo Bianconi if (IS_ERR(wtbl_hdr))
947baa3afb3SLorenzo Bianconi return PTR_ERR(wtbl_hdr);
948baa3afb3SLorenzo Bianconi
949d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx,
950d0e274afSLorenzo Bianconi sta_wtbl, wtbl_hdr);
9516f4d7cc8SLorenzo Bianconi
952fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
953e6d2070dSLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE), true);
9546f4d7cc8SLorenzo Bianconi }
9556f4d7cc8SLorenzo Bianconi
9566f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)9576f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_tx_ba(struct mt7615_dev *dev,
9586f4d7cc8SLorenzo Bianconi struct ieee80211_ampdu_params *params,
9596f4d7cc8SLorenzo Bianconi bool enable)
9606f4d7cc8SLorenzo Bianconi {
9616f4d7cc8SLorenzo Bianconi return mt7615_mcu_sta_ba(dev, params, enable, true);
9626f4d7cc8SLorenzo Bianconi }
9636f4d7cc8SLorenzo Bianconi
9646f4d7cc8SLorenzo Bianconi static int
mt7615_mcu_sta_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)9656f4d7cc8SLorenzo Bianconi mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
9666f4d7cc8SLorenzo Bianconi struct ieee80211_ampdu_params *params,
9676f4d7cc8SLorenzo Bianconi bool enable)
9686f4d7cc8SLorenzo Bianconi {
9696f4d7cc8SLorenzo Bianconi return mt7615_mcu_sta_ba(dev, params, enable, false);
9706f4d7cc8SLorenzo Bianconi }
9716f4d7cc8SLorenzo Bianconi
97299c457d9SLorenzo Bianconi static int
__mt7615_mcu_add_sta(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable,int cmd,bool offload_fw)973d0e274afSLorenzo Bianconi __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,
97482453b1cSLorenzo Bianconi struct ieee80211_sta *sta, bool enable, int cmd,
97582453b1cSLorenzo Bianconi bool offload_fw)
97699c457d9SLorenzo Bianconi {
97799c457d9SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
9785802106fSLorenzo Bianconi struct mt76_sta_cmd_info info = {
9795802106fSLorenzo Bianconi .sta = sta,
9805802106fSLorenzo Bianconi .vif = vif,
98182453b1cSLorenzo Bianconi .offload_fw = offload_fw,
9825802106fSLorenzo Bianconi .enable = enable,
983f5056657SSean Wang .newly = true,
9845802106fSLorenzo Bianconi .cmd = cmd,
9855802106fSLorenzo Bianconi };
98699c457d9SLorenzo Bianconi
9875802106fSLorenzo Bianconi info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid;
988f5056657SSean Wang return mt76_connac_mcu_sta_cmd(phy, &info);
989af44ce4fSLorenzo Bianconi }
990af44ce4fSLorenzo Bianconi
991af44ce4fSLorenzo Bianconi static int
mt7615_mcu_add_sta(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)992d0e274afSLorenzo Bianconi mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
993af44ce4fSLorenzo Bianconi struct ieee80211_sta *sta, bool enable)
994af44ce4fSLorenzo Bianconi {
995d0e274afSLorenzo Bianconi return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
996e6d2070dSLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE), false);
99799c457d9SLorenzo Bianconi }
99899c457d9SLorenzo Bianconi
99954c31b9eSLorenzo Bianconi static int
mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)100054c31b9eSLorenzo Bianconi mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
100154c31b9eSLorenzo Bianconi struct ieee80211_vif *vif,
100254c31b9eSLorenzo Bianconi struct ieee80211_sta *sta)
100354c31b9eSLorenzo Bianconi {
100454c31b9eSLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
100554c31b9eSLorenzo Bianconi
100654c31b9eSLorenzo Bianconi return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
100754c31b9eSLorenzo Bianconi vif, &msta->wcid,
1008e6d2070dSLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE));
100954c31b9eSLorenzo Bianconi }
101054c31b9eSLorenzo Bianconi
10116f4d7cc8SLorenzo Bianconi static const struct mt7615_mcu_ops sta_update_ops = {
1012062c3699SLorenzo Bianconi .add_beacon_offload = mt7615_mcu_add_beacon_offload,
1013062c3699SLorenzo Bianconi .set_pm_state = mt7615_mcu_ctrl_pm_state,
1014062c3699SLorenzo Bianconi .add_dev_info = mt7615_mcu_add_dev,
1015062c3699SLorenzo Bianconi .add_bss_info = mt7615_mcu_add_bss,
10166f4d7cc8SLorenzo Bianconi .add_tx_ba = mt7615_mcu_sta_tx_ba,
10176f4d7cc8SLorenzo Bianconi .add_rx_ba = mt7615_mcu_sta_rx_ba,
101899c457d9SLorenzo Bianconi .sta_add = mt7615_mcu_add_sta,
1019186b659cSLorenzo Bianconi .set_drv_ctrl = mt7615_mcu_drv_pmctrl,
1020186b659cSLorenzo Bianconi .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
102154c31b9eSLorenzo Bianconi .set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans,
10226f4d7cc8SLorenzo Bianconi };
10236f4d7cc8SLorenzo Bianconi
1024af44ce4fSLorenzo Bianconi static int
mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev * dev,int band,int state)102513886067SSean Wang mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
102613886067SSean Wang {
102713886067SSean Wang return 0;
102813886067SSean Wang }
102913886067SSean Wang
103013886067SSean Wang static int
mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)103113886067SSean Wang mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
103213886067SSean Wang struct ieee80211_hw *hw,
103313886067SSean Wang struct ieee80211_vif *vif,
103413886067SSean Wang bool enable)
103513886067SSean Wang {
103613886067SSean Wang struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
103713886067SSean Wang struct mt76_wcid *wcid = &dev->mt76.global_wcid;
103813886067SSean Wang struct ieee80211_mutable_offsets offs;
103913886067SSean Wang struct {
104013886067SSean Wang struct req_hdr {
104113886067SSean Wang u8 bss_idx;
104213886067SSean Wang u8 pad[3];
104313886067SSean Wang } __packed hdr;
104413886067SSean Wang struct bcn_content_tlv {
104513886067SSean Wang __le16 tag;
104613886067SSean Wang __le16 len;
104713886067SSean Wang __le16 tim_ie_pos;
104813886067SSean Wang __le16 csa_ie_pos;
104913886067SSean Wang __le16 bcc_ie_pos;
10508a5a5dbfSRyder Lee /* 0: disable beacon offload
10518a5a5dbfSRyder Lee * 1: enable beacon offload
105213886067SSean Wang * 2: update probe respond offload
105313886067SSean Wang */
105413886067SSean Wang u8 enable;
105513886067SSean Wang /* 0: legacy format (TXD + payload)
105613886067SSean Wang * 1: only cap field IE
105713886067SSean Wang */
105813886067SSean Wang u8 type;
105913886067SSean Wang __le16 pkt_len;
106013886067SSean Wang u8 pkt[512];
106113886067SSean Wang } __packed beacon_tlv;
106213886067SSean Wang } req = {
106313886067SSean Wang .hdr = {
106485d96704SLorenzo Bianconi .bss_idx = mvif->mt76.idx,
106513886067SSean Wang },
106613886067SSean Wang .beacon_tlv = {
106713886067SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
106813886067SSean Wang .len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
106913886067SSean Wang .enable = enable,
107013886067SSean Wang },
107113886067SSean Wang };
107213886067SSean Wang struct sk_buff *skb;
107313886067SSean Wang
10748a5a5dbfSRyder Lee if (!enable)
10758a5a5dbfSRyder Lee goto out;
10768a5a5dbfSRyder Lee
10776e8912a5SShaul Triebitz skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
107813886067SSean Wang if (!skb)
107913886067SSean Wang return -EINVAL;
108013886067SSean Wang
108113886067SSean Wang if (skb->len > 512 - MT_TXD_SIZE) {
108213886067SSean Wang dev_err(dev->mt76.dev, "beacon size limit exceed\n");
108313886067SSean Wang dev_kfree_skb(skb);
108413886067SSean Wang return -EINVAL;
108513886067SSean Wang }
108613886067SSean Wang
108713886067SSean Wang mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
10881d5af0acSFelix Fietkau wcid, NULL, 0, NULL, 0, true);
108913886067SSean Wang memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
109013886067SSean Wang req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
109113886067SSean Wang req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
109213886067SSean Wang
10938552a434SJohn Crispin if (offs.cntdwn_counter_offs[0]) {
109413886067SSean Wang u16 csa_offs;
109513886067SSean Wang
10968552a434SJohn Crispin csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
109713886067SSean Wang req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
109813886067SSean Wang }
109913886067SSean Wang dev_kfree_skb(skb);
110013886067SSean Wang
11018a5a5dbfSRyder Lee out:
110254722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
110313886067SSean Wang &req, sizeof(req), true);
110413886067SSean Wang }
110513886067SSean Wang
110613886067SSean Wang static int
mt7615_mcu_uni_add_dev(struct mt7615_phy * phy,struct ieee80211_vif * vif,bool enable)1107d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1108d0e274afSLorenzo Bianconi bool enable)
1109d0e274afSLorenzo Bianconi {
1110d0e274afSLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
1111d0e274afSLorenzo Bianconi
1112d0e274afSLorenzo Bianconi return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid,
1113d0e274afSLorenzo Bianconi enable);
1114d0e274afSLorenzo Bianconi }
1115d0e274afSLorenzo Bianconi
1116d0e274afSLorenzo Bianconi static int
mt7615_mcu_uni_add_bss(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1117d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1118d0e274afSLorenzo Bianconi struct ieee80211_sta *sta, bool enable)
1119d0e274afSLorenzo Bianconi {
1120d0e274afSLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
1121d0e274afSLorenzo Bianconi
1122d0e274afSLorenzo Bianconi return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
1123a0ab9c31SSean Wang enable, NULL);
1124d0e274afSLorenzo Bianconi }
1125d0e274afSLorenzo Bianconi
1126d0e274afSLorenzo Bianconi static inline int
mt7615_mcu_uni_add_sta(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1127d0e274afSLorenzo Bianconi mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
1128d0e274afSLorenzo Bianconi struct ieee80211_sta *sta, bool enable)
1129d0e274afSLorenzo Bianconi {
1130d0e274afSLorenzo Bianconi return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
113154722402SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), true);
1132d0e274afSLorenzo Bianconi }
1133d0e274afSLorenzo Bianconi
1134d0e274afSLorenzo Bianconi static int
mt7615_mcu_uni_tx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)1135c686a35cSLorenzo Bianconi mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
1136c686a35cSLorenzo Bianconi struct ieee80211_ampdu_params *params,
1137c686a35cSLorenzo Bianconi bool enable)
1138c686a35cSLorenzo Bianconi {
1139d0e274afSLorenzo Bianconi struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv;
1140c686a35cSLorenzo Bianconi
1141d0e274afSLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params,
1142b5322e44SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), enable,
1143b5322e44SLorenzo Bianconi true);
1144c686a35cSLorenzo Bianconi }
1145c686a35cSLorenzo Bianconi
1146c686a35cSLorenzo Bianconi static int
mt7615_mcu_uni_rx_ba(struct mt7615_dev * dev,struct ieee80211_ampdu_params * params,bool enable)1147c686a35cSLorenzo Bianconi mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
1148c686a35cSLorenzo Bianconi struct ieee80211_ampdu_params *params,
1149c686a35cSLorenzo Bianconi bool enable)
1150c686a35cSLorenzo Bianconi {
1151c686a35cSLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
1152c686a35cSLorenzo Bianconi struct mt7615_vif *mvif = msta->vif;
1153c686a35cSLorenzo Bianconi struct wtbl_req_hdr *wtbl_hdr;
1154c686a35cSLorenzo Bianconi struct tlv *sta_wtbl;
1155c686a35cSLorenzo Bianconi struct sk_buff *skb;
1156c686a35cSLorenzo Bianconi int err;
1157c686a35cSLorenzo Bianconi
1158d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1159d0e274afSLorenzo Bianconi &msta->wcid);
1160c686a35cSLorenzo Bianconi if (IS_ERR(skb))
1161c686a35cSLorenzo Bianconi return PTR_ERR(skb);
1162c686a35cSLorenzo Bianconi
1163d0e274afSLorenzo Bianconi mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false);
1164c686a35cSLorenzo Bianconi
1165fa62d0e0SFelix Fietkau err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
116654722402SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), true);
1167c686a35cSLorenzo Bianconi if (err < 0 || !enable)
1168c686a35cSLorenzo Bianconi return err;
1169c686a35cSLorenzo Bianconi
1170d0e274afSLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1171d0e274afSLorenzo Bianconi &msta->wcid);
1172c686a35cSLorenzo Bianconi if (IS_ERR(skb))
1173c686a35cSLorenzo Bianconi return PTR_ERR(skb);
1174c686a35cSLorenzo Bianconi
1175d0e274afSLorenzo Bianconi sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
1176d0e274afSLorenzo Bianconi sizeof(struct tlv));
1177c686a35cSLorenzo Bianconi
1178d0e274afSLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1179d0e274afSLorenzo Bianconi WTBL_SET, sta_wtbl, &skb);
1180c686a35cSLorenzo Bianconi if (IS_ERR(wtbl_hdr))
1181c686a35cSLorenzo Bianconi return PTR_ERR(wtbl_hdr);
1182c686a35cSLorenzo Bianconi
1183d0e274afSLorenzo Bianconi mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false,
1184d0e274afSLorenzo Bianconi sta_wtbl, wtbl_hdr);
1185c686a35cSLorenzo Bianconi
1186fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
118754722402SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), true);
1188c686a35cSLorenzo Bianconi }
1189c686a35cSLorenzo Bianconi
119054c31b9eSLorenzo Bianconi static int
mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)119154c31b9eSLorenzo Bianconi mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev,
119254c31b9eSLorenzo Bianconi struct ieee80211_vif *vif,
119354c31b9eSLorenzo Bianconi struct ieee80211_sta *sta)
119454c31b9eSLorenzo Bianconi {
119554c31b9eSLorenzo Bianconi struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
119654c31b9eSLorenzo Bianconi
119754c31b9eSLorenzo Bianconi return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
119854c31b9eSLorenzo Bianconi vif, &msta->wcid,
119954722402SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE));
120054c31b9eSLorenzo Bianconi }
120154c31b9eSLorenzo Bianconi
1202af44ce4fSLorenzo Bianconi static const struct mt7615_mcu_ops uni_update_ops = {
120313886067SSean Wang .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
120413886067SSean Wang .set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
120513886067SSean Wang .add_dev_info = mt7615_mcu_uni_add_dev,
120613886067SSean Wang .add_bss_info = mt7615_mcu_uni_add_bss,
1207c686a35cSLorenzo Bianconi .add_tx_ba = mt7615_mcu_uni_tx_ba,
1208c686a35cSLorenzo Bianconi .add_rx_ba = mt7615_mcu_uni_rx_ba,
1209af44ce4fSLorenzo Bianconi .sta_add = mt7615_mcu_uni_add_sta,
12106892555dSLorenzo Bianconi .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
1211186b659cSLorenzo Bianconi .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
121254c31b9eSLorenzo Bianconi .set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans,
1213af44ce4fSLorenzo Bianconi };
1214af44ce4fSLorenzo Bianconi
mt7615_mcu_restart(struct mt76_dev * dev)1215e90354e0SLorenzo Bianconi int mt7615_mcu_restart(struct mt76_dev *dev)
121604b8e659SRyder Lee {
1217ffc2198dSLorenzo Bianconi return mt76_mcu_send_msg(dev, MCU_CMD(RESTART_DL_REQ), NULL, 0, true);
121804b8e659SRyder Lee }
1219e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_restart);
122004b8e659SRyder Lee
mt7615_load_patch(struct mt7615_dev * dev,u32 addr,const char * name)122135da599fSFelix Fietkau static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
122204b8e659SRyder Lee {
12232fc44648SLorenzo Bianconi const struct mt7615_patch_hdr *hdr;
12242fc44648SLorenzo Bianconi const struct firmware *fw = NULL;
122504b8e659SRyder Lee int len, ret, sem;
122604b8e659SRyder Lee
1227f2dc8ea1SLorenzo Bianconi ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
122804b8e659SRyder Lee if (ret)
12294efcfd5cSFelix Fietkau return ret;
123004b8e659SRyder Lee
123104b8e659SRyder Lee if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
123204b8e659SRyder Lee dev_err(dev->mt76.dev, "Invalid firmware\n");
123304b8e659SRyder Lee ret = -EINVAL;
12344efcfd5cSFelix Fietkau goto release_fw;
12354efcfd5cSFelix Fietkau }
12364efcfd5cSFelix Fietkau
12374efcfd5cSFelix Fietkau sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
12384efcfd5cSFelix Fietkau switch (sem) {
12394efcfd5cSFelix Fietkau case PATCH_IS_DL:
12404efcfd5cSFelix Fietkau goto release_fw;
12414efcfd5cSFelix Fietkau case PATCH_NOT_DL_SEM_SUCCESS:
12424efcfd5cSFelix Fietkau break;
12434efcfd5cSFelix Fietkau default:
12444efcfd5cSFelix Fietkau dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
12454efcfd5cSFelix Fietkau ret = -EAGAIN;
12464efcfd5cSFelix Fietkau goto release_fw;
124704b8e659SRyder Lee }
124804b8e659SRyder Lee
124904b8e659SRyder Lee hdr = (const struct mt7615_patch_hdr *)(fw->data);
125004b8e659SRyder Lee
125104b8e659SRyder Lee dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
125204b8e659SRyder Lee be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
125304b8e659SRyder Lee
125404b8e659SRyder Lee len = fw->size - sizeof(*hdr);
125504b8e659SRyder Lee
1256d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1257d0e274afSLorenzo Bianconi DL_MODE_NEED_RSP);
125804b8e659SRyder Lee if (ret) {
125904b8e659SRyder Lee dev_err(dev->mt76.dev, "Download request failed\n");
126004b8e659SRyder Lee goto out;
126104b8e659SRyder Lee }
126204b8e659SRyder Lee
1263ffc2198dSLorenzo Bianconi ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
12643cb43b66SLorenzo Bianconi fw->data + sizeof(*hdr), len);
126504b8e659SRyder Lee if (ret) {
126604b8e659SRyder Lee dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
126704b8e659SRyder Lee goto out;
126804b8e659SRyder Lee }
126904b8e659SRyder Lee
1270d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_start_patch(&dev->mt76);
127104b8e659SRyder Lee if (ret)
127204b8e659SRyder Lee dev_err(dev->mt76.dev, "Failed to start patch\n");
127304b8e659SRyder Lee
127404b8e659SRyder Lee out:
1275d0e274afSLorenzo Bianconi sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
127604b8e659SRyder Lee switch (sem) {
127704b8e659SRyder Lee case PATCH_REL_SEM_SUCCESS:
127804b8e659SRyder Lee break;
127904b8e659SRyder Lee default:
128004b8e659SRyder Lee ret = -EAGAIN;
128104b8e659SRyder Lee dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
128204b8e659SRyder Lee break;
128304b8e659SRyder Lee }
128404b8e659SRyder Lee
12854efcfd5cSFelix Fietkau release_fw:
12864efcfd5cSFelix Fietkau release_firmware(fw);
12874efcfd5cSFelix Fietkau
128804b8e659SRyder Lee return ret;
128904b8e659SRyder Lee }
129004b8e659SRyder Lee
12916c6a3fe6SLorenzo Bianconi static int
mt7615_mcu_send_ram_firmware(struct mt7615_dev * dev,const struct mt7615_fw_trailer * hdr,const u8 * data,bool is_cr4)12926c6a3fe6SLorenzo Bianconi mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
12936c6a3fe6SLorenzo Bianconi const struct mt7615_fw_trailer *hdr,
12946c6a3fe6SLorenzo Bianconi const u8 *data, bool is_cr4)
12956c6a3fe6SLorenzo Bianconi {
12966c6a3fe6SLorenzo Bianconi int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM;
12976c6a3fe6SLorenzo Bianconi int err, i, offset = 0;
12986c6a3fe6SLorenzo Bianconi u32 len, addr, mode;
12996c6a3fe6SLorenzo Bianconi
13006c6a3fe6SLorenzo Bianconi for (i = 0; i < n_region; i++) {
13019e90c351SLorenzo Bianconi mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
13029e90c351SLorenzo Bianconi hdr[i].feature_set, is_cr4);
13036c6a3fe6SLorenzo Bianconi len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
13046c6a3fe6SLorenzo Bianconi addr = le32_to_cpu(hdr[i].addr);
13056c6a3fe6SLorenzo Bianconi
1306d0e274afSLorenzo Bianconi err = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1307d0e274afSLorenzo Bianconi mode);
13086c6a3fe6SLorenzo Bianconi if (err) {
13096c6a3fe6SLorenzo Bianconi dev_err(dev->mt76.dev, "Download request failed\n");
13106c6a3fe6SLorenzo Bianconi return err;
13116c6a3fe6SLorenzo Bianconi }
13126c6a3fe6SLorenzo Bianconi
1313ffc2198dSLorenzo Bianconi err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
13143cb43b66SLorenzo Bianconi data + offset, len);
13156c6a3fe6SLorenzo Bianconi if (err) {
13166c6a3fe6SLorenzo Bianconi dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
13176c6a3fe6SLorenzo Bianconi return err;
13186c6a3fe6SLorenzo Bianconi }
13196c6a3fe6SLorenzo Bianconi
13206c6a3fe6SLorenzo Bianconi offset += len;
13216c6a3fe6SLorenzo Bianconi }
13226c6a3fe6SLorenzo Bianconi
13236c6a3fe6SLorenzo Bianconi return 0;
13246c6a3fe6SLorenzo Bianconi }
13256c6a3fe6SLorenzo Bianconi
mt7615_load_n9(struct mt7615_dev * dev,const char * name)13261c88e7e0SFelix Fietkau static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
132704b8e659SRyder Lee {
132804b8e659SRyder Lee const struct mt7615_fw_trailer *hdr;
13299d4d0d06SLorenzo Bianconi const struct firmware *fw;
13306c6a3fe6SLorenzo Bianconi int ret;
133104b8e659SRyder Lee
13321c88e7e0SFelix Fietkau ret = request_firmware(&fw, name, dev->mt76.dev);
133304b8e659SRyder Lee if (ret)
133404b8e659SRyder Lee return ret;
133504b8e659SRyder Lee
133604b8e659SRyder Lee if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) {
133704b8e659SRyder Lee dev_err(dev->mt76.dev, "Invalid firmware\n");
133804b8e659SRyder Lee ret = -EINVAL;
133904b8e659SRyder Lee goto out;
134004b8e659SRyder Lee }
134104b8e659SRyder Lee
134204b8e659SRyder Lee hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
134304b8e659SRyder Lee N9_REGION_NUM * sizeof(*hdr));
134404b8e659SRyder Lee
134504b8e659SRyder Lee dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
134604b8e659SRyder Lee hdr->fw_ver, hdr->build_date);
134704b8e659SRyder Lee
13486c6a3fe6SLorenzo Bianconi ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false);
13496c6a3fe6SLorenzo Bianconi if (ret)
135004b8e659SRyder Lee goto out;
135104b8e659SRyder Lee
1352d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_start_firmware(&dev->mt76,
1353d0e274afSLorenzo Bianconi le32_to_cpu(hdr->addr),
13546c6a3fe6SLorenzo Bianconi FW_START_OVERRIDE);
135504b8e659SRyder Lee if (ret) {
135604b8e659SRyder Lee dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
135704b8e659SRyder Lee goto out;
135804b8e659SRyder Lee }
135904b8e659SRyder Lee
13604e569727SFelix Fietkau snprintf(dev->mt76.hw->wiphy->fw_version,
13614e569727SFelix Fietkau sizeof(dev->mt76.hw->wiphy->fw_version),
13624e569727SFelix Fietkau "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
13634e569727SFelix Fietkau
1364d43c7301SRyder Lee if (!is_mt7615(&dev->mt76)) {
13656849e29eSRyder Lee dev->fw_ver = MT7615_FIRMWARE_V2;
13666f4d7cc8SLorenzo Bianconi dev->mcu_ops = &sta_update_ops;
13676f4d7cc8SLorenzo Bianconi } else {
13686849e29eSRyder Lee dev->fw_ver = MT7615_FIRMWARE_V1;
13696f4d7cc8SLorenzo Bianconi dev->mcu_ops = &wtbl_update_ops;
13706f4d7cc8SLorenzo Bianconi }
13716849e29eSRyder Lee
13721c88e7e0SFelix Fietkau out:
137304b8e659SRyder Lee release_firmware(fw);
13741c88e7e0SFelix Fietkau return ret;
13751c88e7e0SFelix Fietkau }
137604b8e659SRyder Lee
mt7615_load_cr4(struct mt7615_dev * dev,const char * name)13771c88e7e0SFelix Fietkau static int mt7615_load_cr4(struct mt7615_dev *dev, const char *name)
13781c88e7e0SFelix Fietkau {
13791c88e7e0SFelix Fietkau const struct mt7615_fw_trailer *hdr;
13801c88e7e0SFelix Fietkau const struct firmware *fw;
13811c88e7e0SFelix Fietkau int ret;
13821c88e7e0SFelix Fietkau
13831c88e7e0SFelix Fietkau ret = request_firmware(&fw, name, dev->mt76.dev);
138404b8e659SRyder Lee if (ret)
138504b8e659SRyder Lee return ret;
138604b8e659SRyder Lee
138704b8e659SRyder Lee if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) {
138804b8e659SRyder Lee dev_err(dev->mt76.dev, "Invalid firmware\n");
138904b8e659SRyder Lee ret = -EINVAL;
139004b8e659SRyder Lee goto out;
139104b8e659SRyder Lee }
139204b8e659SRyder Lee
139304b8e659SRyder Lee hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
139404b8e659SRyder Lee CR4_REGION_NUM * sizeof(*hdr));
139504b8e659SRyder Lee
139604b8e659SRyder Lee dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
139704b8e659SRyder Lee hdr->fw_ver, hdr->build_date);
139804b8e659SRyder Lee
13996c6a3fe6SLorenzo Bianconi ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true);
14006c6a3fe6SLorenzo Bianconi if (ret)
140104b8e659SRyder Lee goto out;
140204b8e659SRyder Lee
1403d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0,
1404d0e274afSLorenzo Bianconi FW_START_WORKING_PDA_CR4);
1405175b4d58SLorenzo Bianconi if (ret) {
140604b8e659SRyder Lee dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n");
1407175b4d58SLorenzo Bianconi goto out;
1408175b4d58SLorenzo Bianconi }
1409175b4d58SLorenzo Bianconi
141004b8e659SRyder Lee out:
141104b8e659SRyder Lee release_firmware(fw);
141204b8e659SRyder Lee
141304b8e659SRyder Lee return ret;
141404b8e659SRyder Lee }
141504b8e659SRyder Lee
mt7615_load_ram(struct mt7615_dev * dev)14161c88e7e0SFelix Fietkau static int mt7615_load_ram(struct mt7615_dev *dev)
14171c88e7e0SFelix Fietkau {
14181c88e7e0SFelix Fietkau int ret;
14191c88e7e0SFelix Fietkau
14201c88e7e0SFelix Fietkau ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9);
14211c88e7e0SFelix Fietkau if (ret)
14221c88e7e0SFelix Fietkau return ret;
14231c88e7e0SFelix Fietkau
14241c88e7e0SFelix Fietkau return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4);
14251c88e7e0SFelix Fietkau }
14261c88e7e0SFelix Fietkau
mt7615_load_firmware(struct mt7615_dev * dev)142704b8e659SRyder Lee static int mt7615_load_firmware(struct mt7615_dev *dev)
142804b8e659SRyder Lee {
142904b8e659SRyder Lee int ret;
143004b8e659SRyder Lee u32 val;
143104b8e659SRyder Lee
143204b8e659SRyder Lee val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE);
143304b8e659SRyder Lee
143404b8e659SRyder Lee if (val != FW_STATE_FW_DOWNLOAD) {
143504b8e659SRyder Lee dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
143604b8e659SRyder Lee return -EIO;
143704b8e659SRyder Lee }
143804b8e659SRyder Lee
143935da599fSFelix Fietkau ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH);
144004b8e659SRyder Lee if (ret)
144104b8e659SRyder Lee return ret;
144204b8e659SRyder Lee
144304b8e659SRyder Lee ret = mt7615_load_ram(dev);
144404b8e659SRyder Lee if (ret)
144504b8e659SRyder Lee return ret;
144604b8e659SRyder Lee
144704b8e659SRyder Lee if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE,
144804b8e659SRyder Lee FIELD_PREP(MT_TOP_MISC2_FW_STATE,
14495562d5f6SLorenzo Bianconi FW_STATE_RDY), 500)) {
145004b8e659SRyder Lee dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
145104b8e659SRyder Lee return -EIO;
145204b8e659SRyder Lee }
145304b8e659SRyder Lee
145435da599fSFelix Fietkau return 0;
145535da599fSFelix Fietkau }
14565abe8bafSFelix Fietkau
mt7622_load_firmware(struct mt7615_dev * dev)145735da599fSFelix Fietkau static int mt7622_load_firmware(struct mt7615_dev *dev)
145835da599fSFelix Fietkau {
145935da599fSFelix Fietkau int ret;
146035da599fSFelix Fietkau u32 val;
146135da599fSFelix Fietkau
146235da599fSFelix Fietkau mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
146335da599fSFelix Fietkau
146435da599fSFelix Fietkau val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE);
146535da599fSFelix Fietkau if (val != FW_STATE_FW_DOWNLOAD) {
146635da599fSFelix Fietkau dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
146735da599fSFelix Fietkau return -EIO;
146835da599fSFelix Fietkau }
146935da599fSFelix Fietkau
147035da599fSFelix Fietkau ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH);
147135da599fSFelix Fietkau if (ret)
147235da599fSFelix Fietkau return ret;
147335da599fSFelix Fietkau
147435da599fSFelix Fietkau ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9);
147535da599fSFelix Fietkau if (ret)
147635da599fSFelix Fietkau return ret;
147735da599fSFelix Fietkau
147835da599fSFelix Fietkau if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE,
147935da599fSFelix Fietkau FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE,
148035da599fSFelix Fietkau FW_STATE_NORMAL_TRX), 1500)) {
148135da599fSFelix Fietkau dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
148235da599fSFelix Fietkau return -EIO;
148335da599fSFelix Fietkau }
148435da599fSFelix Fietkau
148535da599fSFelix Fietkau mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
148604b8e659SRyder Lee
148704b8e659SRyder Lee return 0;
148804b8e659SRyder Lee }
148904b8e659SRyder Lee
mt7615_mcu_fw_log_2_host(struct mt7615_dev * dev,u8 ctrl)1490f347f81aSFelix Fietkau int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
1491f347f81aSFelix Fietkau {
1492f347f81aSFelix Fietkau struct {
1493f347f81aSFelix Fietkau u8 ctrl_val;
1494f347f81aSFelix Fietkau u8 pad[3];
1495f347f81aSFelix Fietkau } data = {
1496f347f81aSFelix Fietkau .ctrl_val = ctrl
1497f347f81aSFelix Fietkau };
1498f347f81aSFelix Fietkau
1499e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST),
1500e6d2070dSLorenzo Bianconi &data, sizeof(data), true);
1501f347f81aSFelix Fietkau }
1502f347f81aSFelix Fietkau
mt7615_mcu_cal_cache_apply(struct mt7615_dev * dev)150303a25c01SRyder Lee static int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev)
150403a25c01SRyder Lee {
150503a25c01SRyder Lee struct {
150603a25c01SRyder Lee bool cache_enable;
150703a25c01SRyder Lee u8 pad[3];
150803a25c01SRyder Lee } data = {
150903a25c01SRyder Lee .cache_enable = true
151003a25c01SRyder Lee };
151103a25c01SRyder Lee
1512e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(CAL_CACHE), &data,
151303a25c01SRyder Lee sizeof(data), false);
151403a25c01SRyder Lee }
151503a25c01SRyder Lee
mt7663_load_n9(struct mt7615_dev * dev,const char * name)1516f40ac0f3SLorenzo Bianconi static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
1517f40ac0f3SLorenzo Bianconi {
1518404d1cd4SLorenzo Bianconi u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL;
1519049c94f8SLorenzo Bianconi const struct mt76_connac2_fw_trailer *hdr;
1520f40ac0f3SLorenzo Bianconi const struct mt7663_fw_buf *buf;
1521f40ac0f3SLorenzo Bianconi const struct firmware *fw;
1522f40ac0f3SLorenzo Bianconi const u8 *base_addr;
1523f40ac0f3SLorenzo Bianconi int i, ret;
1524f40ac0f3SLorenzo Bianconi
1525f40ac0f3SLorenzo Bianconi ret = request_firmware(&fw, name, dev->mt76.dev);
1526f40ac0f3SLorenzo Bianconi if (ret)
1527f40ac0f3SLorenzo Bianconi return ret;
1528f40ac0f3SLorenzo Bianconi
1529f40ac0f3SLorenzo Bianconi if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) {
1530f40ac0f3SLorenzo Bianconi dev_err(dev->mt76.dev, "Invalid firmware\n");
1531f40ac0f3SLorenzo Bianconi ret = -EINVAL;
1532f40ac0f3SLorenzo Bianconi goto out;
1533f40ac0f3SLorenzo Bianconi }
1534f40ac0f3SLorenzo Bianconi
1535049c94f8SLorenzo Bianconi hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE);
1536f40ac0f3SLorenzo Bianconi dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
1537f40ac0f3SLorenzo Bianconi hdr->fw_ver, hdr->build_date);
1538f40ac0f3SLorenzo Bianconi dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region);
1539f40ac0f3SLorenzo Bianconi
1540f40ac0f3SLorenzo Bianconi base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE;
1541f40ac0f3SLorenzo Bianconi for (i = 0; i < hdr->n_region; i++) {
1542f40ac0f3SLorenzo Bianconi u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE;
1543f40ac0f3SLorenzo Bianconi u32 len, addr, mode;
1544f40ac0f3SLorenzo Bianconi
1545f40ac0f3SLorenzo Bianconi dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i);
1546f40ac0f3SLorenzo Bianconi
1547f40ac0f3SLorenzo Bianconi buf = (const struct mt7663_fw_buf *)(base_addr - shift);
15489e90c351SLorenzo Bianconi mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
15499e90c351SLorenzo Bianconi buf->feature_set, false);
1550f40ac0f3SLorenzo Bianconi addr = le32_to_cpu(buf->img_dest_addr);
1551f40ac0f3SLorenzo Bianconi len = le32_to_cpu(buf->img_size);
1552f40ac0f3SLorenzo Bianconi
1553d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
1554d0e274afSLorenzo Bianconi mode);
1555f40ac0f3SLorenzo Bianconi if (ret) {
1556f40ac0f3SLorenzo Bianconi dev_err(dev->mt76.dev, "Download request failed\n");
1557f40ac0f3SLorenzo Bianconi goto out;
1558f40ac0f3SLorenzo Bianconi }
1559f40ac0f3SLorenzo Bianconi
1560ffc2198dSLorenzo Bianconi ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
15613cb43b66SLorenzo Bianconi fw->data + offset, len);
1562f40ac0f3SLorenzo Bianconi if (ret) {
1563f40ac0f3SLorenzo Bianconi dev_err(dev->mt76.dev, "Failed to send firmware\n");
1564f40ac0f3SLorenzo Bianconi goto out;
1565f40ac0f3SLorenzo Bianconi }
1566f40ac0f3SLorenzo Bianconi
156754178cc1SLorenzo Bianconi offset += le32_to_cpu(buf->img_size);
1568f40ac0f3SLorenzo Bianconi if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) {
1569f40ac0f3SLorenzo Bianconi override_addr = le32_to_cpu(buf->img_dest_addr);
1570f40ac0f3SLorenzo Bianconi dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n",
1571f40ac0f3SLorenzo Bianconi i, override_addr);
1572f40ac0f3SLorenzo Bianconi }
1573f40ac0f3SLorenzo Bianconi }
1574f40ac0f3SLorenzo Bianconi
1575f40ac0f3SLorenzo Bianconi if (override_addr)
1576f40ac0f3SLorenzo Bianconi flag |= FW_START_OVERRIDE;
1577f40ac0f3SLorenzo Bianconi
1578f40ac0f3SLorenzo Bianconi dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n",
1579f40ac0f3SLorenzo Bianconi override_addr, flag);
1580f40ac0f3SLorenzo Bianconi
1581d0e274afSLorenzo Bianconi ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag);
1582938d76bbSLorenzo Bianconi if (ret) {
1583f40ac0f3SLorenzo Bianconi dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
1584938d76bbSLorenzo Bianconi goto out;
1585938d76bbSLorenzo Bianconi }
1586938d76bbSLorenzo Bianconi
1587938d76bbSLorenzo Bianconi snprintf(dev->mt76.hw->wiphy->fw_version,
1588938d76bbSLorenzo Bianconi sizeof(dev->mt76.hw->wiphy->fw_version),
1589938d76bbSLorenzo Bianconi "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
1590f40ac0f3SLorenzo Bianconi
1591f40ac0f3SLorenzo Bianconi out:
1592f40ac0f3SLorenzo Bianconi release_firmware(fw);
1593f40ac0f3SLorenzo Bianconi
1594f40ac0f3SLorenzo Bianconi return ret;
1595f40ac0f3SLorenzo Bianconi }
1596f40ac0f3SLorenzo Bianconi
1597f2dc8ea1SLorenzo Bianconi static int
mt7663_load_rom_patch(struct mt7615_dev * dev,const char ** n9_firmware)1598f2dc8ea1SLorenzo Bianconi mt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware)
1599f2dc8ea1SLorenzo Bianconi {
1600f2dc8ea1SLorenzo Bianconi const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH;
1601f2dc8ea1SLorenzo Bianconi const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH;
1602f2dc8ea1SLorenzo Bianconi int ret;
1603f2dc8ea1SLorenzo Bianconi
1604f2dc8ea1SLorenzo Bianconi if (!prefer_offload_fw) {
1605f2dc8ea1SLorenzo Bianconi secondary_rom = MT7663_OFFLOAD_ROM_PATCH;
1606f2dc8ea1SLorenzo Bianconi primary_rom = MT7663_ROM_PATCH;
1607f2dc8ea1SLorenzo Bianconi }
1608f2dc8ea1SLorenzo Bianconi selected_rom = primary_rom;
1609f2dc8ea1SLorenzo Bianconi
1610f2dc8ea1SLorenzo Bianconi ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom);
1611f2dc8ea1SLorenzo Bianconi if (ret) {
1612f2dc8ea1SLorenzo Bianconi dev_info(dev->mt76.dev, "%s not found, switching to %s",
1613f2dc8ea1SLorenzo Bianconi primary_rom, secondary_rom);
1614f2dc8ea1SLorenzo Bianconi ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS,
1615f2dc8ea1SLorenzo Bianconi secondary_rom);
1616f2dc8ea1SLorenzo Bianconi if (ret) {
1617f2dc8ea1SLorenzo Bianconi dev_err(dev->mt76.dev, "failed to load %s",
1618f2dc8ea1SLorenzo Bianconi secondary_rom);
1619f2dc8ea1SLorenzo Bianconi return ret;
1620f2dc8ea1SLorenzo Bianconi }
1621f2dc8ea1SLorenzo Bianconi selected_rom = secondary_rom;
1622f2dc8ea1SLorenzo Bianconi }
1623f2dc8ea1SLorenzo Bianconi
1624f2dc8ea1SLorenzo Bianconi if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) {
1625f2dc8ea1SLorenzo Bianconi *n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9;
1626f2dc8ea1SLorenzo Bianconi dev->fw_ver = MT7615_FIRMWARE_V3;
1627f2dc8ea1SLorenzo Bianconi dev->mcu_ops = &uni_update_ops;
1628f2dc8ea1SLorenzo Bianconi } else {
1629f2dc8ea1SLorenzo Bianconi *n9_firmware = MT7663_FIRMWARE_N9;
1630f2dc8ea1SLorenzo Bianconi dev->fw_ver = MT7615_FIRMWARE_V2;
1631f2dc8ea1SLorenzo Bianconi dev->mcu_ops = &sta_update_ops;
1632f2dc8ea1SLorenzo Bianconi }
1633f2dc8ea1SLorenzo Bianconi
1634f2dc8ea1SLorenzo Bianconi return 0;
1635f2dc8ea1SLorenzo Bianconi }
1636f2dc8ea1SLorenzo Bianconi
__mt7663_load_firmware(struct mt7615_dev * dev)16378915c3ceSLorenzo Bianconi int __mt7663_load_firmware(struct mt7615_dev *dev)
1638f40ac0f3SLorenzo Bianconi {
1639f2dc8ea1SLorenzo Bianconi const char *n9_firmware;
1640f40ac0f3SLorenzo Bianconi int ret;
1641f40ac0f3SLorenzo Bianconi
1642f40ac0f3SLorenzo Bianconi ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
1643f40ac0f3SLorenzo Bianconi if (ret) {
1644f40ac0f3SLorenzo Bianconi dev_dbg(dev->mt76.dev, "Firmware is already download\n");
1645f40ac0f3SLorenzo Bianconi return -EIO;
1646f40ac0f3SLorenzo Bianconi }
1647f40ac0f3SLorenzo Bianconi
1648f2dc8ea1SLorenzo Bianconi ret = mt7663_load_rom_patch(dev, &n9_firmware);
1649f40ac0f3SLorenzo Bianconi if (ret)
1650f40ac0f3SLorenzo Bianconi return ret;
1651f40ac0f3SLorenzo Bianconi
1652f2dc8ea1SLorenzo Bianconi ret = mt7663_load_n9(dev, n9_firmware);
1653f40ac0f3SLorenzo Bianconi if (ret)
1654f40ac0f3SLorenzo Bianconi return ret;
1655f40ac0f3SLorenzo Bianconi
1656f40ac0f3SLorenzo Bianconi if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
1657f40ac0f3SLorenzo Bianconi MT_TOP_MISC2_FW_N9_RDY, 1500)) {
1658f40ac0f3SLorenzo Bianconi ret = mt76_get_field(dev, MT_CONN_ON_MISC,
1659f40ac0f3SLorenzo Bianconi MT7663_TOP_MISC2_FW_STATE);
1660f40ac0f3SLorenzo Bianconi dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
1661f40ac0f3SLorenzo Bianconi return -EIO;
1662f40ac0f3SLorenzo Bianconi }
1663f40ac0f3SLorenzo Bianconi
1664c6bf2010SLorenzo Bianconi #ifdef CONFIG_PM
1665c6bf2010SLorenzo Bianconi if (mt7615_firmware_offload(dev))
166655d4c19cSLorenzo Bianconi dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
1667c6bf2010SLorenzo Bianconi #endif /* CONFIG_PM */
1668c6bf2010SLorenzo Bianconi
1669f40ac0f3SLorenzo Bianconi dev_dbg(dev->mt76.dev, "Firmware init done\n");
1670f40ac0f3SLorenzo Bianconi
1671f40ac0f3SLorenzo Bianconi return 0;
1672f40ac0f3SLorenzo Bianconi }
16738915c3ceSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt7663_load_firmware);
16748915c3ceSLorenzo Bianconi
mt7663_load_firmware(struct mt7615_dev * dev)16758915c3ceSLorenzo Bianconi static int mt7663_load_firmware(struct mt7615_dev *dev)
16768915c3ceSLorenzo Bianconi {
16778915c3ceSLorenzo Bianconi int ret;
16788915c3ceSLorenzo Bianconi
16798915c3ceSLorenzo Bianconi mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16808915c3ceSLorenzo Bianconi
16818915c3ceSLorenzo Bianconi ret = __mt7663_load_firmware(dev);
16828915c3ceSLorenzo Bianconi if (ret)
16838915c3ceSLorenzo Bianconi return ret;
16848915c3ceSLorenzo Bianconi
16858915c3ceSLorenzo Bianconi mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
16868915c3ceSLorenzo Bianconi
16878915c3ceSLorenzo Bianconi return 0;
16888915c3ceSLorenzo Bianconi }
1689f40ac0f3SLorenzo Bianconi
mt7615_mcu_init(struct mt7615_dev * dev)169004b8e659SRyder Lee int mt7615_mcu_init(struct mt7615_dev *dev)
169104b8e659SRyder Lee {
1692a3a2c2e7SLorenzo Bianconi static const struct mt76_mcu_ops mt7615_mcu_ops = {
1693bb31a80eSLorenzo Bianconi .headroom = sizeof(struct mt7615_mcu_txd),
1694f4d45fe2SLorenzo Bianconi .mcu_skb_send_msg = mt7615_mcu_send_message,
1695f320d812SFelix Fietkau .mcu_parse_response = mt7615_mcu_parse_response,
1696a3a2c2e7SLorenzo Bianconi };
169704b8e659SRyder Lee int ret;
169804b8e659SRyder Lee
1699a3a2c2e7SLorenzo Bianconi dev->mt76.mcu_ops = &mt7615_mcu_ops,
1700a3a2c2e7SLorenzo Bianconi
1701186b659cSLorenzo Bianconi ret = mt7615_mcu_drv_pmctrl(dev);
170204b8e659SRyder Lee if (ret)
170304b8e659SRyder Lee return ret;
170404b8e659SRyder Lee
1705f40ac0f3SLorenzo Bianconi switch (mt76_chip(&dev->mt76)) {
1706f40ac0f3SLorenzo Bianconi case 0x7622:
170735da599fSFelix Fietkau ret = mt7622_load_firmware(dev);
1708f40ac0f3SLorenzo Bianconi break;
1709f40ac0f3SLorenzo Bianconi case 0x7663:
1710f40ac0f3SLorenzo Bianconi ret = mt7663_load_firmware(dev);
1711f40ac0f3SLorenzo Bianconi break;
1712f40ac0f3SLorenzo Bianconi default:
171304b8e659SRyder Lee ret = mt7615_load_firmware(dev);
1714f40ac0f3SLorenzo Bianconi break;
1715f40ac0f3SLorenzo Bianconi }
171604b8e659SRyder Lee if (ret)
171704b8e659SRyder Lee return ret;
171804b8e659SRyder Lee
1719e637763bSLorenzo Bianconi mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
172035da599fSFelix Fietkau dev_dbg(dev->mt76.dev, "Firmware init done\n");
1721011849e0SFelix Fietkau set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
172204b8e659SRyder Lee
172303a25c01SRyder Lee if (dev->dbdc_support) {
172403a25c01SRyder Lee ret = mt7615_mcu_cal_cache_apply(dev);
172503a25c01SRyder Lee if (ret)
172603a25c01SRyder Lee return ret;
172703a25c01SRyder Lee }
172803a25c01SRyder Lee
172903a25c01SRyder Lee return mt7615_mcu_fw_log_2_host(dev, 0);
173004b8e659SRyder Lee }
1731e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_init);
173204b8e659SRyder Lee
mt7615_mcu_exit(struct mt7615_dev * dev)173304b8e659SRyder Lee void mt7615_mcu_exit(struct mt7615_dev *dev)
173404b8e659SRyder Lee {
17358e4edae2SLorenzo Bianconi mt7615_mcu_restart(&dev->mt76);
1736186b659cSLorenzo Bianconi mt7615_mcu_set_fw_ctrl(dev);
173709872957SLorenzo Bianconi skb_queue_purge(&dev->mt76.mcu.res_q);
173804b8e659SRyder Lee }
1739e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mcu_exit);
174004b8e659SRyder Lee
mt7615_mcu_set_eeprom(struct mt7615_dev * dev)174104b8e659SRyder Lee int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
174204b8e659SRyder Lee {
174304b8e659SRyder Lee struct {
174404b8e659SRyder Lee u8 buffer_mode;
1745c321a3d7SLorenzo Bianconi u8 content_format;
174626b48766SRyder Lee __le16 len;
174704b8e659SRyder Lee } __packed req_hdr = {
174804b8e659SRyder Lee .buffer_mode = 1,
174904b8e659SRyder Lee };
1750936fca1fSLorenzo Bianconi u8 *eep = (u8 *)dev->mt76.eeprom.data;
1751936fca1fSLorenzo Bianconi struct sk_buff *skb;
1752c321a3d7SLorenzo Bianconi int eep_len, offset;
175304b8e659SRyder Lee
1754c321a3d7SLorenzo Bianconi switch (mt76_chip(&dev->mt76)) {
1755c321a3d7SLorenzo Bianconi case 0x7622:
17565dff21eeSFelix Fietkau eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0;
1757c321a3d7SLorenzo Bianconi offset = MT_EE_NIC_CONF_0;
1758c321a3d7SLorenzo Bianconi break;
1759c321a3d7SLorenzo Bianconi case 0x7663:
1760c321a3d7SLorenzo Bianconi eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID;
1761c321a3d7SLorenzo Bianconi req_hdr.content_format = 1;
1762c321a3d7SLorenzo Bianconi offset = MT_EE_CHIP_ID;
1763c321a3d7SLorenzo Bianconi break;
1764c321a3d7SLorenzo Bianconi default:
17655dff21eeSFelix Fietkau eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
1766c321a3d7SLorenzo Bianconi offset = MT_EE_NIC_CONF_0;
1767c321a3d7SLorenzo Bianconi break;
1768c321a3d7SLorenzo Bianconi }
17695dff21eeSFelix Fietkau
1770936fca1fSLorenzo Bianconi req_hdr.len = cpu_to_le16(eep_len);
1771936fca1fSLorenzo Bianconi
1772bb31a80eSLorenzo Bianconi skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len);
1773936fca1fSLorenzo Bianconi if (!skb)
1774516c3e38SLorenzo Bianconi return -ENOMEM;
177504b8e659SRyder Lee
1776936fca1fSLorenzo Bianconi skb_put_data(skb, &req_hdr, sizeof(req_hdr));
1777c321a3d7SLorenzo Bianconi skb_put_data(skb, eep + offset, eep_len);
177804b8e659SRyder Lee
1779fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
1780e6d2070dSLorenzo Bianconi MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
178104b8e659SRyder Lee }
178204b8e659SRyder Lee
mt7615_mcu_set_wmm(struct mt7615_dev * dev,u8 queue,const struct ieee80211_tx_queue_params * params)178304b8e659SRyder Lee int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
178404b8e659SRyder Lee const struct ieee80211_tx_queue_params *params)
178504b8e659SRyder Lee {
178604b8e659SRyder Lee #define WMM_AIFS_SET BIT(0)
178704b8e659SRyder Lee #define WMM_CW_MIN_SET BIT(1)
178804b8e659SRyder Lee #define WMM_CW_MAX_SET BIT(2)
178904b8e659SRyder Lee #define WMM_TXOP_SET BIT(3)
17904f8a4f17SRyder Lee #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \
17914f8a4f17SRyder Lee WMM_CW_MAX_SET | WMM_TXOP_SET)
179204b8e659SRyder Lee struct req_data {
179304b8e659SRyder Lee u8 number;
179404b8e659SRyder Lee u8 rsv[3];
179504b8e659SRyder Lee u8 queue;
179604b8e659SRyder Lee u8 valid;
179704b8e659SRyder Lee u8 aifs;
179804b8e659SRyder Lee u8 cw_min;
179904b8e659SRyder Lee __le16 cw_max;
180004b8e659SRyder Lee __le16 txop;
180104b8e659SRyder Lee } __packed req = {
180204b8e659SRyder Lee .number = 1,
180304b8e659SRyder Lee .queue = queue,
18044f8a4f17SRyder Lee .valid = WMM_PARAM_SET,
180504b8e659SRyder Lee .aifs = params->aifs,
18064f8a4f17SRyder Lee .cw_min = 5,
18074f8a4f17SRyder Lee .cw_max = cpu_to_le16(10),
180804b8e659SRyder Lee .txop = cpu_to_le16(params->txop),
180904b8e659SRyder Lee };
181004b8e659SRyder Lee
18114f8a4f17SRyder Lee if (params->cw_min)
18124f8a4f17SRyder Lee req.cw_min = fls(params->cw_min);
18134f8a4f17SRyder Lee if (params->cw_max)
18144f8a4f17SRyder Lee req.cw_max = cpu_to_le16(fls(params->cw_max));
181504b8e659SRyder Lee
1816e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE),
1817e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
181804b8e659SRyder Lee }
181904b8e659SRyder Lee
mt7615_mcu_set_dbdc(struct mt7615_dev * dev)1820ac3ef85cSFelix Fietkau int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
1821ac3ef85cSFelix Fietkau {
1822ac3ef85cSFelix Fietkau struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
1823ac3ef85cSFelix Fietkau struct dbdc_entry {
1824ac3ef85cSFelix Fietkau u8 type;
1825ac3ef85cSFelix Fietkau u8 index;
1826ac3ef85cSFelix Fietkau u8 band;
1827ac3ef85cSFelix Fietkau u8 _rsv;
1828ac3ef85cSFelix Fietkau };
1829ac3ef85cSFelix Fietkau struct {
1830ac3ef85cSFelix Fietkau u8 enable;
1831ac3ef85cSFelix Fietkau u8 num;
1832ac3ef85cSFelix Fietkau u8 _rsv[2];
1833ac3ef85cSFelix Fietkau struct dbdc_entry entry[64];
1834ac3ef85cSFelix Fietkau } req = {
1835ac3ef85cSFelix Fietkau .enable = !!ext_phy,
1836ac3ef85cSFelix Fietkau };
1837ac3ef85cSFelix Fietkau int i;
1838ac3ef85cSFelix Fietkau
1839ac3ef85cSFelix Fietkau if (!ext_phy)
1840ac3ef85cSFelix Fietkau goto out;
1841ac3ef85cSFelix Fietkau
1842ac3ef85cSFelix Fietkau #define ADD_DBDC_ENTRY(_type, _idx, _band) \
1843ac3ef85cSFelix Fietkau do { \
1844ac3ef85cSFelix Fietkau req.entry[req.num].type = _type; \
1845ac3ef85cSFelix Fietkau req.entry[req.num].index = _idx; \
1846ac3ef85cSFelix Fietkau req.entry[req.num++].band = _band; \
1847ac3ef85cSFelix Fietkau } while (0)
1848ac3ef85cSFelix Fietkau
1849ac3ef85cSFelix Fietkau for (i = 0; i < 4; i++) {
1850d8d59f66SRyder Lee bool band = !!(ext_phy->omac_mask & BIT_ULL(i));
1851ac3ef85cSFelix Fietkau
1852ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band);
1853ac3ef85cSFelix Fietkau }
1854ac3ef85cSFelix Fietkau
1855ac3ef85cSFelix Fietkau for (i = 0; i < 14; i++) {
1856d8d59f66SRyder Lee bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i));
1857ac3ef85cSFelix Fietkau
1858ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band);
1859ac3ef85cSFelix Fietkau }
1860ac3ef85cSFelix Fietkau
1861ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1);
1862ac3ef85cSFelix Fietkau
1863ac3ef85cSFelix Fietkau for (i = 0; i < 3; i++)
1864ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1);
1865ac3ef85cSFelix Fietkau
1866ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0);
1867ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0);
1868ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1);
1869ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1);
1870ac3ef85cSFelix Fietkau
1871ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0);
1872ac3ef85cSFelix Fietkau ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1);
1873ac3ef85cSFelix Fietkau
1874ac3ef85cSFelix Fietkau out:
1875e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DBDC_CTRL), &req,
1876cb5cdd4cSFelix Fietkau sizeof(req), true);
1877ac3ef85cSFelix Fietkau }
1878ac3ef85cSFelix Fietkau
mt7615_mcu_del_wtbl_all(struct mt7615_dev * dev)187904b8e659SRyder Lee int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
188004b8e659SRyder Lee {
1881516c3e38SLorenzo Bianconi struct wtbl_req_hdr req = {
1882516c3e38SLorenzo Bianconi .operation = WTBL_RESET_ALL,
18830467448dSLorenzo Bianconi };
188404b8e659SRyder Lee
1885e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WTBL_UPDATE),
1886e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
188704b8e659SRyder Lee }
188804b8e659SRyder Lee
mt7615_mcu_set_fcc5_lpn(struct mt7615_dev * dev,int val)18892ce73efeSLorenzo Bianconi int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val)
18902ce73efeSLorenzo Bianconi {
18912ce73efeSLorenzo Bianconi struct {
18920211c282SLorenzo Bianconi __le16 tag;
18930211c282SLorenzo Bianconi __le16 min_lpn;
18942ce73efeSLorenzo Bianconi } req = {
18950211c282SLorenzo Bianconi .tag = cpu_to_le16(0x1),
18960211c282SLorenzo Bianconi .min_lpn = cpu_to_le16(val),
18972ce73efeSLorenzo Bianconi };
18982ce73efeSLorenzo Bianconi
18999d8d136cSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19009d8d136cSLorenzo Bianconi &req, sizeof(req), true);
19012ce73efeSLorenzo Bianconi }
19022ce73efeSLorenzo Bianconi
mt7615_mcu_set_pulse_th(struct mt7615_dev * dev,const struct mt7615_dfs_pulse * pulse)19032ce73efeSLorenzo Bianconi int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
19042ce73efeSLorenzo Bianconi const struct mt7615_dfs_pulse *pulse)
19052ce73efeSLorenzo Bianconi {
19062ce73efeSLorenzo Bianconi struct {
19070211c282SLorenzo Bianconi __le16 tag;
19080211c282SLorenzo Bianconi __le32 max_width; /* us */
19090211c282SLorenzo Bianconi __le32 max_pwr; /* dbm */
19100211c282SLorenzo Bianconi __le32 min_pwr; /* dbm */
19110211c282SLorenzo Bianconi __le32 min_stgr_pri; /* us */
19120211c282SLorenzo Bianconi __le32 max_stgr_pri; /* us */
19130211c282SLorenzo Bianconi __le32 min_cr_pri; /* us */
19140211c282SLorenzo Bianconi __le32 max_cr_pri; /* us */
19152ce73efeSLorenzo Bianconi } req = {
19160211c282SLorenzo Bianconi .tag = cpu_to_le16(0x3),
19170211c282SLorenzo Bianconi #define __req_field(field) .field = cpu_to_le32(pulse->field)
19180211c282SLorenzo Bianconi __req_field(max_width),
19190211c282SLorenzo Bianconi __req_field(max_pwr),
19200211c282SLorenzo Bianconi __req_field(min_pwr),
19210211c282SLorenzo Bianconi __req_field(min_stgr_pri),
19220211c282SLorenzo Bianconi __req_field(max_stgr_pri),
19230211c282SLorenzo Bianconi __req_field(min_cr_pri),
19240211c282SLorenzo Bianconi __req_field(max_cr_pri),
19250211c282SLorenzo Bianconi #undef __req_field
19262ce73efeSLorenzo Bianconi };
19272ce73efeSLorenzo Bianconi
19289d8d136cSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19299d8d136cSLorenzo Bianconi &req, sizeof(req), true);
19302ce73efeSLorenzo Bianconi }
19312ce73efeSLorenzo Bianconi
mt7615_mcu_set_radar_th(struct mt7615_dev * dev,int index,const struct mt7615_dfs_pattern * pattern)19322ce73efeSLorenzo Bianconi int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
19332ce73efeSLorenzo Bianconi const struct mt7615_dfs_pattern *pattern)
19342ce73efeSLorenzo Bianconi {
19352ce73efeSLorenzo Bianconi struct {
19360211c282SLorenzo Bianconi __le16 tag;
19370211c282SLorenzo Bianconi __le16 radar_type;
19380211c282SLorenzo Bianconi u8 enb;
19390211c282SLorenzo Bianconi u8 stgr;
19400211c282SLorenzo Bianconi u8 min_crpn;
19410211c282SLorenzo Bianconi u8 max_crpn;
19420211c282SLorenzo Bianconi u8 min_crpr;
19430211c282SLorenzo Bianconi u8 min_pw;
19440211c282SLorenzo Bianconi u8 max_pw;
19450211c282SLorenzo Bianconi __le32 min_pri;
19460211c282SLorenzo Bianconi __le32 max_pri;
19470211c282SLorenzo Bianconi u8 min_crbn;
19480211c282SLorenzo Bianconi u8 max_crbn;
19490211c282SLorenzo Bianconi u8 min_stgpn;
19500211c282SLorenzo Bianconi u8 max_stgpn;
19510211c282SLorenzo Bianconi u8 min_stgpr;
19522ce73efeSLorenzo Bianconi } req = {
19530211c282SLorenzo Bianconi .tag = cpu_to_le16(0x2),
19540211c282SLorenzo Bianconi .radar_type = cpu_to_le16(index),
19550211c282SLorenzo Bianconi #define __req_field_u8(field) .field = pattern->field
19560211c282SLorenzo Bianconi #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
19570211c282SLorenzo Bianconi __req_field_u8(enb),
19580211c282SLorenzo Bianconi __req_field_u8(stgr),
19590211c282SLorenzo Bianconi __req_field_u8(min_crpn),
19600211c282SLorenzo Bianconi __req_field_u8(max_crpn),
19610211c282SLorenzo Bianconi __req_field_u8(min_crpr),
19620211c282SLorenzo Bianconi __req_field_u8(min_pw),
19630211c282SLorenzo Bianconi __req_field_u8(max_pw),
19640211c282SLorenzo Bianconi __req_field_u32(min_pri),
19650211c282SLorenzo Bianconi __req_field_u32(max_pri),
19660211c282SLorenzo Bianconi __req_field_u8(min_crbn),
19670211c282SLorenzo Bianconi __req_field_u8(max_crbn),
19680211c282SLorenzo Bianconi __req_field_u8(min_stgpn),
19690211c282SLorenzo Bianconi __req_field_u8(max_stgpn),
19700211c282SLorenzo Bianconi __req_field_u8(min_stgpr),
19710211c282SLorenzo Bianconi #undef __req_field_u8
19720211c282SLorenzo Bianconi #undef __req_field_u32
19732ce73efeSLorenzo Bianconi };
19742ce73efeSLorenzo Bianconi
19759d8d136cSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH),
19769d8d136cSLorenzo Bianconi &req, sizeof(req), true);
19772ce73efeSLorenzo Bianconi }
19782ce73efeSLorenzo Bianconi
mt7615_mcu_rdd_send_pattern(struct mt7615_dev * dev)197970911d96SLorenzo Bianconi int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
198070911d96SLorenzo Bianconi {
198170911d96SLorenzo Bianconi struct {
198270911d96SLorenzo Bianconi u8 pulse_num;
198370911d96SLorenzo Bianconi u8 rsv[3];
198470911d96SLorenzo Bianconi struct {
19850211c282SLorenzo Bianconi __le32 start_time;
19860211c282SLorenzo Bianconi __le16 width;
19870211c282SLorenzo Bianconi __le16 power;
198870911d96SLorenzo Bianconi } pattern[32];
198970911d96SLorenzo Bianconi } req = {
199070911d96SLorenzo Bianconi .pulse_num = dev->radar_pattern.n_pulses,
199170911d96SLorenzo Bianconi };
199270911d96SLorenzo Bianconi u32 start_time = ktime_to_ms(ktime_get_boottime());
199370911d96SLorenzo Bianconi int i;
199470911d96SLorenzo Bianconi
199570911d96SLorenzo Bianconi if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern))
199670911d96SLorenzo Bianconi return -EINVAL;
199770911d96SLorenzo Bianconi
199870911d96SLorenzo Bianconi /* TODO: add some noise here */
199970911d96SLorenzo Bianconi for (i = 0; i < dev->radar_pattern.n_pulses; i++) {
20000211c282SLorenzo Bianconi u32 ts = start_time + i * dev->radar_pattern.period;
20010211c282SLorenzo Bianconi
20020211c282SLorenzo Bianconi req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width);
20030211c282SLorenzo Bianconi req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power);
20040211c282SLorenzo Bianconi req.pattern[i].start_time = cpu_to_le32(ts);
200570911d96SLorenzo Bianconi }
200670911d96SLorenzo Bianconi
2007e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_PATTERN),
200870911d96SLorenzo Bianconi &req, sizeof(req), false);
200970911d96SLorenzo Bianconi }
201070911d96SLorenzo Bianconi
mt7615_mcu_set_txpower_sku(struct mt7615_phy * phy,u8 * sku)201115d9a5d7SFelix Fietkau static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
201215d9a5d7SFelix Fietkau {
201315d9a5d7SFelix Fietkau struct mt76_phy *mphy = phy->mt76;
201415d9a5d7SFelix Fietkau struct ieee80211_hw *hw = mphy->hw;
2015fb0d9054SFelix Fietkau struct mt76_power_limits limits;
2016fb0d9054SFelix Fietkau s8 *limits_array = (s8 *)&limits;
201715d9a5d7SFelix Fietkau int n_chains = hweight8(mphy->antenna_mask);
2018148950e5SLorenzo Bianconi int tx_power = hw->conf.power_level * 2;
201915d9a5d7SFelix Fietkau int i;
2020fb0d9054SFelix Fietkau static const u8 sku_mapping[] = {
2021fb0d9054SFelix Fietkau #define SKU_FIELD(_type, _field) \
2022fb0d9054SFelix Fietkau [MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field)
2023fb0d9054SFelix Fietkau SKU_FIELD(CCK_1_2, cck[0]),
2024fb0d9054SFelix Fietkau SKU_FIELD(CCK_55_11, cck[2]),
2025fb0d9054SFelix Fietkau SKU_FIELD(OFDM_6_9, ofdm[0]),
2026fb0d9054SFelix Fietkau SKU_FIELD(OFDM_12_18, ofdm[2]),
2027fb0d9054SFelix Fietkau SKU_FIELD(OFDM_24_36, ofdm[4]),
2028fb0d9054SFelix Fietkau SKU_FIELD(OFDM_48, ofdm[6]),
2029fb0d9054SFelix Fietkau SKU_FIELD(OFDM_54, ofdm[7]),
2030fb0d9054SFelix Fietkau SKU_FIELD(HT20_0_8, mcs[0][0]),
2031fb0d9054SFelix Fietkau SKU_FIELD(HT20_32, ofdm[0]),
2032fb0d9054SFelix Fietkau SKU_FIELD(HT20_1_2_9_10, mcs[0][1]),
2033fb0d9054SFelix Fietkau SKU_FIELD(HT20_3_4_11_12, mcs[0][3]),
2034fb0d9054SFelix Fietkau SKU_FIELD(HT20_5_13, mcs[0][5]),
2035fb0d9054SFelix Fietkau SKU_FIELD(HT20_6_14, mcs[0][6]),
2036fb0d9054SFelix Fietkau SKU_FIELD(HT20_7_15, mcs[0][7]),
2037fb0d9054SFelix Fietkau SKU_FIELD(HT40_0_8, mcs[1][0]),
2038fb0d9054SFelix Fietkau SKU_FIELD(HT40_32, ofdm[0]),
2039fb0d9054SFelix Fietkau SKU_FIELD(HT40_1_2_9_10, mcs[1][1]),
2040fb0d9054SFelix Fietkau SKU_FIELD(HT40_3_4_11_12, mcs[1][3]),
2041fb0d9054SFelix Fietkau SKU_FIELD(HT40_5_13, mcs[1][5]),
2042fb0d9054SFelix Fietkau SKU_FIELD(HT40_6_14, mcs[1][6]),
2043fb0d9054SFelix Fietkau SKU_FIELD(HT40_7_15, mcs[1][7]),
2044fb0d9054SFelix Fietkau SKU_FIELD(VHT20_0, mcs[0][0]),
2045fb0d9054SFelix Fietkau SKU_FIELD(VHT20_1_2, mcs[0][1]),
2046fb0d9054SFelix Fietkau SKU_FIELD(VHT20_3_4, mcs[0][3]),
2047fb0d9054SFelix Fietkau SKU_FIELD(VHT20_5_6, mcs[0][5]),
2048fb0d9054SFelix Fietkau SKU_FIELD(VHT20_7, mcs[0][7]),
2049fb0d9054SFelix Fietkau SKU_FIELD(VHT20_8, mcs[0][8]),
2050fb0d9054SFelix Fietkau SKU_FIELD(VHT20_9, mcs[0][9]),
2051fb0d9054SFelix Fietkau SKU_FIELD(VHT40_0, mcs[1][0]),
2052fb0d9054SFelix Fietkau SKU_FIELD(VHT40_1_2, mcs[1][1]),
2053fb0d9054SFelix Fietkau SKU_FIELD(VHT40_3_4, mcs[1][3]),
2054fb0d9054SFelix Fietkau SKU_FIELD(VHT40_5_6, mcs[1][5]),
2055fb0d9054SFelix Fietkau SKU_FIELD(VHT40_7, mcs[1][7]),
2056fb0d9054SFelix Fietkau SKU_FIELD(VHT40_8, mcs[1][8]),
2057fb0d9054SFelix Fietkau SKU_FIELD(VHT40_9, mcs[1][9]),
2058fb0d9054SFelix Fietkau SKU_FIELD(VHT80_0, mcs[2][0]),
2059fb0d9054SFelix Fietkau SKU_FIELD(VHT80_1_2, mcs[2][1]),
2060fb0d9054SFelix Fietkau SKU_FIELD(VHT80_3_4, mcs[2][3]),
2061fb0d9054SFelix Fietkau SKU_FIELD(VHT80_5_6, mcs[2][5]),
2062fb0d9054SFelix Fietkau SKU_FIELD(VHT80_7, mcs[2][7]),
2063fb0d9054SFelix Fietkau SKU_FIELD(VHT80_8, mcs[2][8]),
2064fb0d9054SFelix Fietkau SKU_FIELD(VHT80_9, mcs[2][9]),
2065fb0d9054SFelix Fietkau SKU_FIELD(VHT160_0, mcs[3][0]),
2066fb0d9054SFelix Fietkau SKU_FIELD(VHT160_1_2, mcs[3][1]),
2067fb0d9054SFelix Fietkau SKU_FIELD(VHT160_3_4, mcs[3][3]),
2068fb0d9054SFelix Fietkau SKU_FIELD(VHT160_5_6, mcs[3][5]),
2069fb0d9054SFelix Fietkau SKU_FIELD(VHT160_7, mcs[3][7]),
2070fb0d9054SFelix Fietkau SKU_FIELD(VHT160_8, mcs[3][8]),
2071fb0d9054SFelix Fietkau SKU_FIELD(VHT160_9, mcs[3][9]),
2072fb0d9054SFelix Fietkau #undef SKU_FIELD
2073fb0d9054SFelix Fietkau };
207415d9a5d7SFelix Fietkau
2075148950e5SLorenzo Bianconi tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power);
2076148950e5SLorenzo Bianconi tx_power -= mt76_tx_power_nss_delta(n_chains);
2077fb0d9054SFelix Fietkau tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
2078fb0d9054SFelix Fietkau &limits, tx_power);
207915d9a5d7SFelix Fietkau mphy->txpower_cur = tx_power;
208015d9a5d7SFelix Fietkau
2081729d3dbdSLorenzo Bianconi if (is_mt7663(mphy->dev)) {
2082729d3dbdSLorenzo Bianconi memset(sku, tx_power, MT_SKU_4SS_DELTA + 1);
2083729d3dbdSLorenzo Bianconi return;
2084729d3dbdSLorenzo Bianconi }
2085729d3dbdSLorenzo Bianconi
208615d9a5d7SFelix Fietkau for (i = 0; i < MT_SKU_1SS_DELTA; i++)
2087fb0d9054SFelix Fietkau sku[i] = limits_array[sku_mapping[i]];
208815d9a5d7SFelix Fietkau
208915d9a5d7SFelix Fietkau for (i = 0; i < 4; i++) {
209015d9a5d7SFelix Fietkau int delta = 0;
209115d9a5d7SFelix Fietkau
209215d9a5d7SFelix Fietkau if (i < n_chains - 1)
209307cda406SFelix Fietkau delta = mt76_tx_power_nss_delta(n_chains) -
209407cda406SFelix Fietkau mt76_tx_power_nss_delta(i + 1);
209515d9a5d7SFelix Fietkau sku[MT_SKU_1SS_DELTA + i] = delta;
209615d9a5d7SFelix Fietkau }
209715d9a5d7SFelix Fietkau }
209815d9a5d7SFelix Fietkau
mt7615_mcu_chan_bw(struct cfg80211_chan_def * chandef)2099ad380ad1SFelix Fietkau static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef)
2100ad380ad1SFelix Fietkau {
2101ad380ad1SFelix Fietkau static const u8 width_to_bw[] = {
2102ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
2103ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
2104ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
2105ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
2106ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
2107ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
2108ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
2109ad380ad1SFelix Fietkau [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
2110ad380ad1SFelix Fietkau };
2111ad380ad1SFelix Fietkau
2112ad380ad1SFelix Fietkau if (chandef->width >= ARRAY_SIZE(width_to_bw))
2113ad380ad1SFelix Fietkau return 0;
2114ad380ad1SFelix Fietkau
2115ad380ad1SFelix Fietkau return width_to_bw[chandef->width];
2116ad380ad1SFelix Fietkau }
2117ad380ad1SFelix Fietkau
mt7615_mcu_set_chan_info(struct mt7615_phy * phy,int cmd)21184fe9218cSRyder Lee int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
211904b8e659SRyder Lee {
2120fdd2e570SFelix Fietkau struct mt7615_dev *dev = phy->dev;
2121fdd2e570SFelix Fietkau struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
212202fc62e3SLorenzo Bianconi int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
212304b8e659SRyder Lee struct {
212404b8e659SRyder Lee u8 control_chan;
212504b8e659SRyder Lee u8 center_chan;
212604b8e659SRyder Lee u8 bw;
212704b8e659SRyder Lee u8 tx_streams;
212804b8e659SRyder Lee u8 rx_streams_mask;
212904b8e659SRyder Lee u8 switch_reason;
213004b8e659SRyder Lee u8 band_idx;
213104b8e659SRyder Lee /* for 80+80 only */
213204b8e659SRyder Lee u8 center_chan2;
213304b8e659SRyder Lee __le16 cac_case;
213404b8e659SRyder Lee u8 channel_band;
213504b8e659SRyder Lee u8 rsv0;
213604b8e659SRyder Lee __le32 outband_freq;
213704b8e659SRyder Lee u8 txpower_drop;
213804b8e659SRyder Lee u8 rsv1[3];
213904b8e659SRyder Lee u8 txpower_sku[53];
214004b8e659SRyder Lee u8 rsv2[3];
214102fc62e3SLorenzo Bianconi } req = {
214202fc62e3SLorenzo Bianconi .control_chan = chandef->chan->hw_value,
214302fc62e3SLorenzo Bianconi .center_chan = ieee80211_frequency_to_channel(freq1),
21444fe9218cSRyder Lee .tx_streams = hweight8(phy->mt76->antenna_mask),
2145b9027e08SLorenzo Bianconi .rx_streams_mask = phy->mt76->chainmask,
214602fc62e3SLorenzo Bianconi .center_chan2 = ieee80211_frequency_to_channel(freq2),
214702fc62e3SLorenzo Bianconi };
214804b8e659SRyder Lee
214924e69f6bSDeren Wu if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
2150*94ed41a7SShayne Chen phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
215100a883e6SFelix Fietkau req.switch_reason = CH_SWITCH_NORMAL;
215200a883e6SFelix Fietkau else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
21532b5d1b91SLorenzo Bianconi req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
215400a883e6SFelix Fietkau else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
215500a883e6SFelix Fietkau NL80211_IFTYPE_AP))
215602fc62e3SLorenzo Bianconi req.switch_reason = CH_SWITCH_DFS;
215702fc62e3SLorenzo Bianconi else
215804b8e659SRyder Lee req.switch_reason = CH_SWITCH_NORMAL;
215904b8e659SRyder Lee
2160fdd2e570SFelix Fietkau req.band_idx = phy != &dev->phy;
2161ad380ad1SFelix Fietkau req.bw = mt7615_mcu_chan_bw(chandef);
216215d9a5d7SFelix Fietkau
2163c918c74dSShayne Chen if (mt76_testmode_enabled(phy->mt76))
21644f0bce1cSFelix Fietkau memset(req.txpower_sku, 0x3f, 49);
21654f0bce1cSFelix Fietkau else
216615d9a5d7SFelix Fietkau mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);
216704b8e659SRyder Lee
2168cb5cdd4cSFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
216904b8e659SRyder Lee }
217004b8e659SRyder Lee
mt7615_mcu_get_temperature(struct mt7615_dev * dev)2171109e505aSRyder Lee int mt7615_mcu_get_temperature(struct mt7615_dev *dev)
21720e6a29e4SLorenzo Bianconi {
21730e6a29e4SLorenzo Bianconi struct {
21740e6a29e4SLorenzo Bianconi u8 action;
21750e6a29e4SLorenzo Bianconi u8 rsv[3];
2176109e505aSRyder Lee } req = {};
21770e6a29e4SLorenzo Bianconi
21789d8d136cSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL),
2179e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
21800e6a29e4SLorenzo Bianconi }
218115d9a5d7SFelix Fietkau
mt7615_mcu_set_test_param(struct mt7615_dev * dev,u8 param,bool test_mode,u32 val)21824f0bce1cSFelix Fietkau int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
21834f0bce1cSFelix Fietkau u32 val)
21844f0bce1cSFelix Fietkau {
21854f0bce1cSFelix Fietkau struct {
21864f0bce1cSFelix Fietkau u8 test_mode_en;
21874f0bce1cSFelix Fietkau u8 param_idx;
21884f0bce1cSFelix Fietkau u8 _rsv[2];
21894f0bce1cSFelix Fietkau
21904f0bce1cSFelix Fietkau __le32 value;
21914f0bce1cSFelix Fietkau
21924f0bce1cSFelix Fietkau u8 pad[8];
21934f0bce1cSFelix Fietkau } req = {
21944f0bce1cSFelix Fietkau .test_mode_en = test_mode,
21954f0bce1cSFelix Fietkau .param_idx = param,
21964f0bce1cSFelix Fietkau .value = cpu_to_le32(val),
21974f0bce1cSFelix Fietkau };
21984f0bce1cSFelix Fietkau
2199e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
2200e6d2070dSLorenzo Bianconi &req, sizeof(req), false);
22014f0bce1cSFelix Fietkau }
22024f0bce1cSFelix Fietkau
mt7615_mcu_set_sku_en(struct mt7615_phy * phy,bool enable)220315d9a5d7SFelix Fietkau int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
220415d9a5d7SFelix Fietkau {
220515d9a5d7SFelix Fietkau struct mt7615_dev *dev = phy->dev;
220615d9a5d7SFelix Fietkau struct {
220715d9a5d7SFelix Fietkau u8 format_id;
220815d9a5d7SFelix Fietkau u8 sku_enable;
220915d9a5d7SFelix Fietkau u8 band_idx;
221015d9a5d7SFelix Fietkau u8 rsv;
221115d9a5d7SFelix Fietkau } req = {
221215d9a5d7SFelix Fietkau .format_id = 0,
221315d9a5d7SFelix Fietkau .band_idx = phy != &dev->phy,
221415d9a5d7SFelix Fietkau .sku_enable = enable,
221515d9a5d7SFelix Fietkau };
221615d9a5d7SFelix Fietkau
2217cb5cdd4cSFelix Fietkau return mt76_mcu_send_msg(&dev->mt76,
2218e6d2070dSLorenzo Bianconi MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
2219e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
222015d9a5d7SFelix Fietkau }
2221bf18fcdcSLorenzo Bianconi
mt7615_find_freq_idx(const u16 * freqs,int n_freqs,u16 cur)2222ad380ad1SFelix Fietkau static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
2223ad380ad1SFelix Fietkau {
2224ad380ad1SFelix Fietkau int i;
2225ad380ad1SFelix Fietkau
2226ad380ad1SFelix Fietkau for (i = 0; i < n_freqs; i++)
2227ad380ad1SFelix Fietkau if (cur == freqs[i])
2228ad380ad1SFelix Fietkau return i;
2229ad380ad1SFelix Fietkau
2230ad380ad1SFelix Fietkau return -1;
2231ad380ad1SFelix Fietkau }
2232ad380ad1SFelix Fietkau
mt7615_dcoc_freq_idx(u16 freq,u8 bw)2233ad380ad1SFelix Fietkau static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
2234ad380ad1SFelix Fietkau {
2235ad380ad1SFelix Fietkau static const u16 freq_list[] = {
2236ad380ad1SFelix Fietkau 4980, 5805, 5905, 5190,
2237ad380ad1SFelix Fietkau 5230, 5270, 5310, 5350,
2238ad380ad1SFelix Fietkau 5390, 5430, 5470, 5510,
2239ad380ad1SFelix Fietkau 5550, 5590, 5630, 5670,
2240ad380ad1SFelix Fietkau 5710, 5755, 5795, 5835,
2241ad380ad1SFelix Fietkau 5875, 5210, 5290, 5370,
2242ad380ad1SFelix Fietkau 5450, 5530, 5610, 5690,
2243ad380ad1SFelix Fietkau 5775, 5855
2244ad380ad1SFelix Fietkau };
2245ad380ad1SFelix Fietkau static const u16 freq_bw40[] = {
2246ad380ad1SFelix Fietkau 5190, 5230, 5270, 5310,
2247ad380ad1SFelix Fietkau 5350, 5390, 5430, 5470,
2248ad380ad1SFelix Fietkau 5510, 5550, 5590, 5630,
2249ad380ad1SFelix Fietkau 5670, 5710, 5755, 5795,
2250ad380ad1SFelix Fietkau 5835, 5875
2251ad380ad1SFelix Fietkau };
2252ad380ad1SFelix Fietkau int offset_2g = ARRAY_SIZE(freq_list);
2253ad380ad1SFelix Fietkau int idx;
2254ad380ad1SFelix Fietkau
2255ad380ad1SFelix Fietkau if (freq < 4000) {
2256ad380ad1SFelix Fietkau if (freq < 2427)
2257ad380ad1SFelix Fietkau return offset_2g;
2258ad380ad1SFelix Fietkau if (freq < 2442)
2259ad380ad1SFelix Fietkau return offset_2g + 1;
2260ad380ad1SFelix Fietkau if (freq < 2457)
2261ad380ad1SFelix Fietkau return offset_2g + 2;
2262ad380ad1SFelix Fietkau
2263ad380ad1SFelix Fietkau return offset_2g + 3;
2264ad380ad1SFelix Fietkau }
2265ad380ad1SFelix Fietkau
2266ad380ad1SFelix Fietkau switch (bw) {
2267ad380ad1SFelix Fietkau case NL80211_CHAN_WIDTH_80:
2268ad380ad1SFelix Fietkau case NL80211_CHAN_WIDTH_80P80:
2269ad380ad1SFelix Fietkau case NL80211_CHAN_WIDTH_160:
2270ad380ad1SFelix Fietkau break;
2271ad380ad1SFelix Fietkau default:
2272ad380ad1SFelix Fietkau idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2273ad380ad1SFelix Fietkau freq + 10);
2274ad380ad1SFelix Fietkau if (idx >= 0) {
2275ad380ad1SFelix Fietkau freq = freq_bw40[idx];
2276ad380ad1SFelix Fietkau break;
2277ad380ad1SFelix Fietkau }
2278ad380ad1SFelix Fietkau
2279ad380ad1SFelix Fietkau idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2280ad380ad1SFelix Fietkau freq - 10);
2281ad380ad1SFelix Fietkau if (idx >= 0) {
2282ad380ad1SFelix Fietkau freq = freq_bw40[idx];
2283ad380ad1SFelix Fietkau break;
2284ad380ad1SFelix Fietkau }
2285aab662ccSGustavo A. R. Silva fallthrough;
2286ad380ad1SFelix Fietkau case NL80211_CHAN_WIDTH_40:
2287ad380ad1SFelix Fietkau idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
2288ad380ad1SFelix Fietkau freq);
2289ad380ad1SFelix Fietkau if (idx >= 0)
2290ad380ad1SFelix Fietkau break;
2291ad380ad1SFelix Fietkau
2292ad380ad1SFelix Fietkau return -1;
2293ad380ad1SFelix Fietkau
2294ad380ad1SFelix Fietkau }
2295ad380ad1SFelix Fietkau
2296ad380ad1SFelix Fietkau return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2297ad380ad1SFelix Fietkau }
2298ad380ad1SFelix Fietkau
mt7615_mcu_apply_rx_dcoc(struct mt7615_phy * phy)2299ad380ad1SFelix Fietkau int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy)
2300ad380ad1SFelix Fietkau {
2301ad380ad1SFelix Fietkau struct mt7615_dev *dev = phy->dev;
2302ad380ad1SFelix Fietkau struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2303ad380ad1SFelix Fietkau int freq2 = chandef->center_freq2;
2304ad380ad1SFelix Fietkau int ret;
2305ad380ad1SFelix Fietkau struct {
2306ad380ad1SFelix Fietkau u8 direction;
2307ad380ad1SFelix Fietkau u8 runtime_calibration;
2308ad380ad1SFelix Fietkau u8 _rsv[2];
2309ad380ad1SFelix Fietkau
2310ad380ad1SFelix Fietkau __le16 center_freq;
2311ad380ad1SFelix Fietkau u8 bw;
2312ad380ad1SFelix Fietkau u8 band;
2313ad380ad1SFelix Fietkau u8 is_freq2;
2314ad380ad1SFelix Fietkau u8 success;
2315ad380ad1SFelix Fietkau u8 dbdc_en;
2316ad380ad1SFelix Fietkau
2317ad380ad1SFelix Fietkau u8 _rsv2;
2318ad380ad1SFelix Fietkau
2319ad380ad1SFelix Fietkau struct {
2320ad380ad1SFelix Fietkau __le32 sx0_i_lna[4];
2321ad380ad1SFelix Fietkau __le32 sx0_q_lna[4];
2322ad380ad1SFelix Fietkau
2323ad380ad1SFelix Fietkau __le32 sx2_i_lna[4];
2324ad380ad1SFelix Fietkau __le32 sx2_q_lna[4];
2325ad380ad1SFelix Fietkau } dcoc_data[4];
2326ad380ad1SFelix Fietkau } req = {
2327ad380ad1SFelix Fietkau .direction = 1,
2328ad380ad1SFelix Fietkau
2329ad380ad1SFelix Fietkau .bw = mt7615_mcu_chan_bw(chandef),
2330ad380ad1SFelix Fietkau .band = chandef->center_freq1 > 4000,
2331dc44c45cSLorenzo Bianconi .dbdc_en = !!dev->mt76.phys[MT_BAND1],
2332ad380ad1SFelix Fietkau };
2333ad380ad1SFelix Fietkau u16 center_freq = chandef->center_freq1;
2334ad380ad1SFelix Fietkau int freq_idx;
2335ad380ad1SFelix Fietkau u8 *eep = dev->mt76.eeprom.data;
2336ad380ad1SFelix Fietkau
2337ad380ad1SFelix Fietkau if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL))
2338ad380ad1SFelix Fietkau return 0;
2339ad380ad1SFelix Fietkau
2340ad380ad1SFelix Fietkau if (chandef->width == NL80211_CHAN_WIDTH_160) {
2341ad380ad1SFelix Fietkau freq2 = center_freq + 40;
2342ad380ad1SFelix Fietkau center_freq -= 40;
2343ad380ad1SFelix Fietkau }
2344ad380ad1SFelix Fietkau
2345ad380ad1SFelix Fietkau again:
2346ad380ad1SFelix Fietkau req.runtime_calibration = 1;
2347ad380ad1SFelix Fietkau freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width);
2348ad380ad1SFelix Fietkau if (freq_idx < 0)
2349ad380ad1SFelix Fietkau goto out;
2350ad380ad1SFelix Fietkau
2351ad380ad1SFelix Fietkau memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET +
2352ad380ad1SFelix Fietkau freq_idx * MT7615_EEPROM_DCOC_SIZE,
2353ad380ad1SFelix Fietkau sizeof(req.dcoc_data));
2354ad380ad1SFelix Fietkau req.runtime_calibration = 0;
2355ad380ad1SFelix Fietkau
2356ad380ad1SFelix Fietkau out:
2357ad380ad1SFelix Fietkau req.center_freq = cpu_to_le16(center_freq);
2358e6d2070dSLorenzo Bianconi ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RXDCOC_CAL), &req,
2359ad380ad1SFelix Fietkau sizeof(req), true);
2360ad380ad1SFelix Fietkau
2361ad380ad1SFelix Fietkau if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
2362ad380ad1SFelix Fietkau chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
2363ad380ad1SFelix Fietkau req.is_freq2 = true;
2364ad380ad1SFelix Fietkau center_freq = freq2;
2365ad380ad1SFelix Fietkau goto again;
2366ad380ad1SFelix Fietkau }
2367ad380ad1SFelix Fietkau
2368ad380ad1SFelix Fietkau return ret;
2369ad380ad1SFelix Fietkau }
2370371a59d1SFelix Fietkau
mt7615_dpd_freq_idx(u16 freq,u8 bw)2371371a59d1SFelix Fietkau static int mt7615_dpd_freq_idx(u16 freq, u8 bw)
2372371a59d1SFelix Fietkau {
2373371a59d1SFelix Fietkau static const u16 freq_list[] = {
2374371a59d1SFelix Fietkau 4920, 4940, 4960, 4980,
2375371a59d1SFelix Fietkau 5040, 5060, 5080, 5180,
2376371a59d1SFelix Fietkau 5200, 5220, 5240, 5260,
2377371a59d1SFelix Fietkau 5280, 5300, 5320, 5340,
2378371a59d1SFelix Fietkau 5360, 5380, 5400, 5420,
2379371a59d1SFelix Fietkau 5440, 5460, 5480, 5500,
2380371a59d1SFelix Fietkau 5520, 5540, 5560, 5580,
2381371a59d1SFelix Fietkau 5600, 5620, 5640, 5660,
2382371a59d1SFelix Fietkau 5680, 5700, 5720, 5745,
2383371a59d1SFelix Fietkau 5765, 5785, 5805, 5825,
2384371a59d1SFelix Fietkau 5845, 5865, 5885, 5905
2385371a59d1SFelix Fietkau };
2386371a59d1SFelix Fietkau int offset_2g = ARRAY_SIZE(freq_list);
2387371a59d1SFelix Fietkau int idx;
2388371a59d1SFelix Fietkau
2389371a59d1SFelix Fietkau if (freq < 4000) {
2390371a59d1SFelix Fietkau if (freq < 2432)
2391371a59d1SFelix Fietkau return offset_2g;
2392371a59d1SFelix Fietkau if (freq < 2457)
2393371a59d1SFelix Fietkau return offset_2g + 1;
2394371a59d1SFelix Fietkau
2395371a59d1SFelix Fietkau return offset_2g + 2;
2396371a59d1SFelix Fietkau }
2397371a59d1SFelix Fietkau
2398371a59d1SFelix Fietkau if (bw != NL80211_CHAN_WIDTH_20) {
2399371a59d1SFelix Fietkau idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2400371a59d1SFelix Fietkau freq + 10);
2401371a59d1SFelix Fietkau if (idx >= 0)
2402371a59d1SFelix Fietkau return idx;
2403371a59d1SFelix Fietkau
2404371a59d1SFelix Fietkau idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2405371a59d1SFelix Fietkau freq - 10);
2406371a59d1SFelix Fietkau if (idx >= 0)
2407371a59d1SFelix Fietkau return idx;
2408371a59d1SFelix Fietkau }
2409371a59d1SFelix Fietkau
2410371a59d1SFelix Fietkau return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2411371a59d1SFelix Fietkau }
2412371a59d1SFelix Fietkau
2413371a59d1SFelix Fietkau
mt7615_mcu_apply_tx_dpd(struct mt7615_phy * phy)2414371a59d1SFelix Fietkau int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy)
2415371a59d1SFelix Fietkau {
2416371a59d1SFelix Fietkau struct mt7615_dev *dev = phy->dev;
2417371a59d1SFelix Fietkau struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2418371a59d1SFelix Fietkau int freq2 = chandef->center_freq2;
2419371a59d1SFelix Fietkau int ret;
2420371a59d1SFelix Fietkau struct {
2421371a59d1SFelix Fietkau u8 direction;
2422371a59d1SFelix Fietkau u8 runtime_calibration;
2423371a59d1SFelix Fietkau u8 _rsv[2];
2424371a59d1SFelix Fietkau
2425371a59d1SFelix Fietkau __le16 center_freq;
2426371a59d1SFelix Fietkau u8 bw;
2427371a59d1SFelix Fietkau u8 band;
2428371a59d1SFelix Fietkau u8 is_freq2;
2429371a59d1SFelix Fietkau u8 success;
2430371a59d1SFelix Fietkau u8 dbdc_en;
2431371a59d1SFelix Fietkau
2432371a59d1SFelix Fietkau u8 _rsv2;
2433371a59d1SFelix Fietkau
2434371a59d1SFelix Fietkau struct {
2435371a59d1SFelix Fietkau struct {
2436371a59d1SFelix Fietkau u32 dpd_g0;
2437371a59d1SFelix Fietkau u8 data[32];
2438371a59d1SFelix Fietkau } wf0, wf1;
2439371a59d1SFelix Fietkau
2440371a59d1SFelix Fietkau struct {
2441371a59d1SFelix Fietkau u32 dpd_g0_prim;
2442371a59d1SFelix Fietkau u32 dpd_g0_sec;
2443371a59d1SFelix Fietkau u8 data_prim[32];
2444371a59d1SFelix Fietkau u8 data_sec[32];
2445371a59d1SFelix Fietkau } wf2, wf3;
2446371a59d1SFelix Fietkau } dpd_data;
2447371a59d1SFelix Fietkau } req = {
2448371a59d1SFelix Fietkau .direction = 1,
2449371a59d1SFelix Fietkau
2450371a59d1SFelix Fietkau .bw = mt7615_mcu_chan_bw(chandef),
2451371a59d1SFelix Fietkau .band = chandef->center_freq1 > 4000,
2452dc44c45cSLorenzo Bianconi .dbdc_en = !!dev->mt76.phys[MT_BAND1],
2453371a59d1SFelix Fietkau };
2454371a59d1SFelix Fietkau u16 center_freq = chandef->center_freq1;
2455371a59d1SFelix Fietkau int freq_idx;
2456371a59d1SFelix Fietkau u8 *eep = dev->mt76.eeprom.data;
2457371a59d1SFelix Fietkau
2458371a59d1SFelix Fietkau if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD))
2459371a59d1SFelix Fietkau return 0;
2460371a59d1SFelix Fietkau
2461371a59d1SFelix Fietkau if (chandef->width == NL80211_CHAN_WIDTH_160) {
2462371a59d1SFelix Fietkau freq2 = center_freq + 40;
2463371a59d1SFelix Fietkau center_freq -= 40;
2464371a59d1SFelix Fietkau }
2465371a59d1SFelix Fietkau
2466371a59d1SFelix Fietkau again:
2467371a59d1SFelix Fietkau req.runtime_calibration = 1;
2468371a59d1SFelix Fietkau freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width);
2469371a59d1SFelix Fietkau if (freq_idx < 0)
2470371a59d1SFelix Fietkau goto out;
2471371a59d1SFelix Fietkau
2472371a59d1SFelix Fietkau memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET +
2473371a59d1SFelix Fietkau freq_idx * MT7615_EEPROM_TXDPD_SIZE,
2474371a59d1SFelix Fietkau sizeof(req.dpd_data));
2475371a59d1SFelix Fietkau req.runtime_calibration = 0;
2476371a59d1SFelix Fietkau
2477371a59d1SFelix Fietkau out:
2478371a59d1SFelix Fietkau req.center_freq = cpu_to_le16(center_freq);
2479e6d2070dSLorenzo Bianconi ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXDPD_CAL),
2480e6d2070dSLorenzo Bianconi &req, sizeof(req), true);
2481371a59d1SFelix Fietkau
2482371a59d1SFelix Fietkau if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
2483371a59d1SFelix Fietkau chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
2484371a59d1SFelix Fietkau req.is_freq2 = true;
2485371a59d1SFelix Fietkau center_freq = freq2;
2486371a59d1SFelix Fietkau goto again;
2487371a59d1SFelix Fietkau }
2488371a59d1SFelix Fietkau
2489371a59d1SFelix Fietkau return ret;
2490371a59d1SFelix Fietkau }
24916f117852SSean Wang
mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev * dev)2492d4b98c63SRyder Lee int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev)
2493d4b98c63SRyder Lee {
2494d4b98c63SRyder Lee struct {
2495d4b98c63SRyder Lee u8 operation;
2496d4b98c63SRyder Lee u8 count;
2497d4b98c63SRyder Lee u8 _rsv[2];
2498d4b98c63SRyder Lee u8 index;
2499d4b98c63SRyder Lee u8 enable;
2500d4b98c63SRyder Lee __le16 etype;
2501d4b98c63SRyder Lee } req = {
2502d4b98c63SRyder Lee .operation = 1,
2503d4b98c63SRyder Lee .count = 1,
2504d4b98c63SRyder Lee .enable = 1,
2505d4b98c63SRyder Lee .etype = cpu_to_le16(ETH_P_PAE),
2506d4b98c63SRyder Lee };
2507d4b98c63SRyder Lee
2508e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
2509d4b98c63SRyder Lee &req, sizeof(req), false);
2510d4b98c63SRyder Lee }
2511d4b98c63SRyder Lee
mt7615_mcu_set_bss_pm(struct mt7615_dev * dev,struct ieee80211_vif * vif,bool enable)251283b9f42aSLorenzo Bianconi int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
2513c6bf2010SLorenzo Bianconi bool enable)
2514c6bf2010SLorenzo Bianconi {
2515c6bf2010SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
2516c6bf2010SLorenzo Bianconi struct {
2517c6bf2010SLorenzo Bianconi u8 bss_idx;
2518c6bf2010SLorenzo Bianconi u8 dtim_period;
2519c6bf2010SLorenzo Bianconi __le16 aid;
2520c6bf2010SLorenzo Bianconi __le16 bcn_interval;
2521c6bf2010SLorenzo Bianconi __le16 atim_window;
2522c6bf2010SLorenzo Bianconi u8 uapsd;
2523c6bf2010SLorenzo Bianconi u8 bmc_delivered_ac;
2524c6bf2010SLorenzo Bianconi u8 bmc_triggered_ac;
2525c6bf2010SLorenzo Bianconi u8 pad;
2526c6bf2010SLorenzo Bianconi } req = {
252785d96704SLorenzo Bianconi .bss_idx = mvif->mt76.idx,
2528f276e20bSJohannes Berg .aid = cpu_to_le16(vif->cfg.aid),
2529c6bf2010SLorenzo Bianconi .dtim_period = vif->bss_conf.dtim_period,
2530c6bf2010SLorenzo Bianconi .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
2531c6bf2010SLorenzo Bianconi };
2532c6bf2010SLorenzo Bianconi struct {
2533c6bf2010SLorenzo Bianconi u8 bss_idx;
2534c6bf2010SLorenzo Bianconi u8 pad[3];
2535c6bf2010SLorenzo Bianconi } req_hdr = {
253685d96704SLorenzo Bianconi .bss_idx = mvif->mt76.idx,
2537c6bf2010SLorenzo Bianconi };
2538c6bf2010SLorenzo Bianconi int err;
2539c6bf2010SLorenzo Bianconi
25407124198aSLorenzo Bianconi if (vif->type != NL80211_IFTYPE_STATION)
25417124198aSLorenzo Bianconi return 0;
2542c6bf2010SLorenzo Bianconi
2543680a2eadSLorenzo Bianconi err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
2544680a2eadSLorenzo Bianconi &req_hdr, sizeof(req_hdr), false);
2545c6bf2010SLorenzo Bianconi if (err < 0 || !enable)
2546c6bf2010SLorenzo Bianconi return err;
2547c6bf2010SLorenzo Bianconi
2548680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
2549680a2eadSLorenzo Bianconi &req, sizeof(req), false);
2550c6bf2010SLorenzo Bianconi }
2551c6bf2010SLorenzo Bianconi
mt7615_mcu_set_roc(struct mt7615_phy * phy,struct ieee80211_vif * vif,struct ieee80211_channel * chan,int duration)25527307f296SLorenzo Bianconi int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
25537307f296SLorenzo Bianconi struct ieee80211_channel *chan, int duration)
25547307f296SLorenzo Bianconi {
25557307f296SLorenzo Bianconi struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
25567307f296SLorenzo Bianconi struct mt7615_dev *dev = phy->dev;
25577307f296SLorenzo Bianconi struct mt7615_roc_tlv req = {
255885d96704SLorenzo Bianconi .bss_idx = mvif->mt76.idx,
25597307f296SLorenzo Bianconi .active = !chan,
25607307f296SLorenzo Bianconi .max_interval = cpu_to_le32(duration),
25617307f296SLorenzo Bianconi .primary_chan = chan ? chan->hw_value : 0,
25627307f296SLorenzo Bianconi .band = chan ? chan->band : 0,
25637307f296SLorenzo Bianconi .req_type = 2,
25647307f296SLorenzo Bianconi };
25657307f296SLorenzo Bianconi
25667307f296SLorenzo Bianconi phy->roc_grant = false;
25677307f296SLorenzo Bianconi
2568680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
2569680a2eadSLorenzo Bianconi &req, sizeof(req), false);
25707307f296SLorenzo Bianconi }
2571