xref: /linux/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c (revision 9494a6c2e4f6ce21a1e6885145171f90c4492131)
1 /*
2  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
3  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <linux/kernel.h>
19 #include <linux/firmware.h>
20 #include <linux/delay.h>
21 
22 #include "mt76x2.h"
23 #include "mcu.h"
24 #include "eeprom.h"
25 
26 int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw,
27 			   u8 bw_index, bool scan)
28 {
29 	struct sk_buff *skb;
30 	struct {
31 		u8 idx;
32 		u8 scan;
33 		u8 bw;
34 		u8 _pad0;
35 
36 		__le16 chainmask;
37 		u8 ext_chan;
38 		u8 _pad1;
39 
40 	} __packed __aligned(4) msg = {
41 		.idx = channel,
42 		.scan = scan,
43 		.bw = bw,
44 		.chainmask = cpu_to_le16(dev->mt76.chainmask),
45 	};
46 
47 	/* first set the channel without the extension channel info */
48 	skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
49 	mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
50 
51 	usleep_range(5000, 10000);
52 
53 	msg.ext_chan = 0xe0 + bw_index;
54 	skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
55 	return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
56 }
57 EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
58 
59 int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
60 		       u8 channel)
61 {
62 	struct mt76_dev *mdev = &dev->mt76;
63 	struct sk_buff *skb;
64 	struct {
65 		u8 cr_mode;
66 		u8 temp;
67 		u8 ch;
68 		u8 _pad0;
69 
70 		__le32 cfg;
71 	} __packed __aligned(4) msg = {
72 		.cr_mode = type,
73 		.temp = temp_level,
74 		.ch = channel,
75 	};
76 	u32 val;
77 
78 	val = BIT(31);
79 	val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
80 	val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
81 	msg.cfg = cpu_to_le32(val);
82 
83 	/* first set the channel without the extension channel info */
84 	skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
85 	return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true);
86 }
87 EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr);
88 
89 int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain,
90 			 bool force)
91 {
92 	struct sk_buff *skb;
93 	struct {
94 		__le32 channel;
95 		__le32 gain_val;
96 	} __packed __aligned(4) msg = {
97 		.channel = cpu_to_le32(channel),
98 		.gain_val = cpu_to_le32(gain),
99 	};
100 
101 	if (force)
102 		msg.channel |= cpu_to_le32(BIT(31));
103 
104 	skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
105 	return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true);
106 }
107 EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain);
108 
109 int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev,
110 			 struct mt76x2_tssi_comp *tssi_data)
111 {
112 	struct sk_buff *skb;
113 	struct {
114 		__le32 id;
115 		struct mt76x2_tssi_comp data;
116 	} __packed __aligned(4) msg = {
117 		.id = cpu_to_le32(MCU_CAL_TSSI_COMP),
118 		.data = *tssi_data,
119 	};
120 
121 	skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
122 	return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true);
123 }
124 EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp);
125