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 sk_buff *skb; 63 struct { 64 u8 cr_mode; 65 u8 temp; 66 u8 ch; 67 u8 _pad0; 68 69 __le32 cfg; 70 } __packed __aligned(4) msg = { 71 .cr_mode = type, 72 .temp = temp_level, 73 .ch = channel, 74 }; 75 u32 val; 76 77 val = BIT(31); 78 val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; 79 val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; 80 msg.cfg = cpu_to_le32(val); 81 82 /* first set the channel without the extension channel info */ 83 skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); 84 return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); 85 } 86 EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); 87 88 int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, 89 bool force) 90 { 91 struct sk_buff *skb; 92 struct { 93 __le32 channel; 94 __le32 gain_val; 95 } __packed __aligned(4) msg = { 96 .channel = cpu_to_le32(channel), 97 .gain_val = cpu_to_le32(gain), 98 }; 99 100 if (force) 101 msg.channel |= cpu_to_le32(BIT(31)); 102 103 skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); 104 return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); 105 } 106 EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); 107 108 int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, 109 struct mt76x2_tssi_comp *tssi_data) 110 { 111 struct sk_buff *skb; 112 struct { 113 __le32 id; 114 struct mt76x2_tssi_comp data; 115 } __packed __aligned(4) msg = { 116 .id = cpu_to_le32(MCU_CAL_TSSI_COMP), 117 .data = *tssi_data, 118 }; 119 120 skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); 121 return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); 122 } 123 EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp); 124