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