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