1  // SPDX-License-Identifier: ISC
2  /*
3   * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
4   * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
5   */
6  
7  #include <linux/kernel.h>
8  #include <linux/firmware.h>
9  #include <linux/delay.h>
10  
11  #include "mt76x02_mcu.h"
12  
mt76x02_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)13  int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
14  			       struct sk_buff *skb, int seq)
15  {
16  	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
17  	u32 *rxfce;
18  
19  	if (!skb) {
20  		dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
21  			abs(cmd), seq);
22  		dev->mcu_timeout = 1;
23  		return -ETIMEDOUT;
24  	}
25  
26  	rxfce = (u32 *)skb->cb;
27  	if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
28  		return -EAGAIN;
29  
30  	return 0;
31  }
32  EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response);
33  
mt76x02_mcu_msg_send(struct mt76_dev * mdev,int cmd,const void * data,int len,bool wait_resp)34  int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
35  			 int len, bool wait_resp)
36  {
37  	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
38  	unsigned long expires = jiffies + HZ;
39  	struct sk_buff *skb;
40  	u32 tx_info;
41  	int ret;
42  	u8 seq;
43  
44  	if (dev->mcu_timeout)
45  		return -EIO;
46  
47  	skb = mt76_mcu_msg_alloc(mdev, data, len);
48  	if (!skb)
49  		return -ENOMEM;
50  
51  	mutex_lock(&mdev->mcu.mutex);
52  
53  	seq = ++mdev->mcu.msg_seq & 0xf;
54  	if (!seq)
55  		seq = ++mdev->mcu.msg_seq & 0xf;
56  
57  	tx_info = MT_MCU_MSG_TYPE_CMD |
58  		  FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
59  		  FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
60  		  FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
61  		  FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
62  
63  	ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info);
64  	if (ret)
65  		goto out;
66  
67  	while (wait_resp) {
68  		skb = mt76_mcu_get_response(&dev->mt76, expires);
69  		ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq);
70  		dev_kfree_skb(skb);
71  		if (ret != -EAGAIN)
72  			break;
73  	}
74  
75  out:
76  	mutex_unlock(&mdev->mcu.mutex);
77  
78  	return ret;
79  }
80  EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send);
81  
mt76x02_mcu_function_select(struct mt76x02_dev * dev,enum mcu_function func,u32 val)82  int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
83  				u32 val)
84  {
85  	struct {
86  		__le32 id;
87  		__le32 value;
88  	} __packed __aligned(4) msg = {
89  		.id = cpu_to_le32(func),
90  		.value = cpu_to_le32(val),
91  	};
92  	bool wait = false;
93  
94  	if (func != Q_SELECT)
95  		wait = true;
96  
97  	return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg,
98  				 sizeof(msg), wait);
99  }
100  EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
101  
mt76x02_mcu_set_radio_state(struct mt76x02_dev * dev,bool on)102  int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on)
103  {
104  	struct {
105  		__le32 mode;
106  		__le32 level;
107  	} __packed __aligned(4) msg = {
108  		.mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
109  		.level = cpu_to_le32(0),
110  	};
111  
112  	return mt76_mcu_send_msg(&dev->mt76, CMD_POWER_SAVING_OP, &msg,
113  				 sizeof(msg), false);
114  }
115  EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
116  
mt76x02_mcu_calibrate(struct mt76x02_dev * dev,int type,u32 param)117  int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
118  {
119  	struct {
120  		__le32 id;
121  		__le32 value;
122  	} __packed __aligned(4) msg = {
123  		.id = cpu_to_le32(type),
124  		.value = cpu_to_le32(param),
125  	};
126  	bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev);
127  	int ret;
128  
129  	if (is_mt76x2e)
130  		mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
131  
132  	ret = mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
133  				sizeof(msg), true);
134  	if (ret)
135  		return ret;
136  
137  	if (is_mt76x2e &&
138  	    WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0,
139  				    BIT(31), BIT(31), 100)))
140  		return -ETIMEDOUT;
141  
142  	return 0;
143  }
144  EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate);
145  
mt76x02_mcu_cleanup(struct mt76x02_dev * dev)146  int mt76x02_mcu_cleanup(struct mt76x02_dev *dev)
147  {
148  	struct sk_buff *skb;
149  
150  	mt76_wr(dev, MT_MCU_INT_LEVEL, 1);
151  	usleep_range(20000, 30000);
152  
153  	while ((skb = skb_dequeue(&dev->mt76.mcu.res_q)) != NULL)
154  		dev_kfree_skb(skb);
155  
156  	return 0;
157  }
158  EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup);
159  
mt76x02_set_ethtool_fwver(struct mt76x02_dev * dev,const struct mt76x02_fw_header * h)160  void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev,
161  			       const struct mt76x02_fw_header *h)
162  {
163  	u16 bld = le16_to_cpu(h->build_ver);
164  	u16 ver = le16_to_cpu(h->fw_ver);
165  
166  	snprintf(dev->mt76.hw->wiphy->fw_version,
167  		 sizeof(dev->mt76.hw->wiphy->fw_version),
168  		 "%d.%d.%02d-b%x",
169  		 (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld);
170  }
171  EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver);
172