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