1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/firmware.h> 9 #include <linux/delay.h> 10 11 #include "mt76x02_mcu.h" 12 13 int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd, 14 struct sk_buff *skb, int seq) 15 { 16 struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 17 u32 *rxfce; 18 19 if (!skb) { 20 dev_err(mdev->dev, 21 "MCU message %d (seq %d) timed out\n", cmd, 22 seq); 23 dev->mcu_timeout = 1; 24 return -ETIMEDOUT; 25 } 26 27 rxfce = (u32 *)skb->cb; 28 if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) 29 return -EAGAIN; 30 31 return 0; 32 } 33 EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response); 34 35 int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 36 int len, bool wait_resp) 37 { 38 struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 39 unsigned long expires = jiffies + HZ; 40 struct sk_buff *skb; 41 u32 tx_info; 42 int ret; 43 u8 seq; 44 45 if (dev->mcu_timeout) 46 return -EIO; 47 48 skb = mt76_mcu_msg_alloc(mdev, data, len); 49 if (!skb) 50 return -ENOMEM; 51 52 mutex_lock(&mdev->mcu.mutex); 53 54 seq = ++mdev->mcu.msg_seq & 0xf; 55 if (!seq) 56 seq = ++mdev->mcu.msg_seq & 0xf; 57 58 tx_info = MT_MCU_MSG_TYPE_CMD | 59 FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | 60 FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | 61 FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | 62 FIELD_PREP(MT_MCU_MSG_LEN, skb->len); 63 64 ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info); 65 if (ret) 66 goto out; 67 68 while (wait_resp) { 69 skb = mt76_mcu_get_response(&dev->mt76, expires); 70 ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq); 71 dev_kfree_skb(skb); 72 if (ret != -EAGAIN) 73 break; 74 } 75 76 out: 77 mutex_unlock(&mdev->mcu.mutex); 78 79 return ret; 80 } 81 EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send); 82 83 int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, 84 u32 val) 85 { 86 struct { 87 __le32 id; 88 __le32 value; 89 } __packed __aligned(4) msg = { 90 .id = cpu_to_le32(func), 91 .value = cpu_to_le32(val), 92 }; 93 bool wait = false; 94 95 if (func != Q_SELECT) 96 wait = true; 97 98 return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg, 99 sizeof(msg), wait); 100 } 101 EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select); 102 103 int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on) 104 { 105 struct { 106 __le32 mode; 107 __le32 level; 108 } __packed __aligned(4) msg = { 109 .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), 110 .level = cpu_to_le32(0), 111 }; 112 113 return mt76_mcu_send_msg(&dev->mt76, CMD_POWER_SAVING_OP, &msg, 114 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->mt76) && 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->mt76, CMD_CALIBRATION_OP, &msg, 134 sizeof(msg), 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.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