17f17b86aSRyder Lee // SPDX-License-Identifier: ISC 2c8846e10SFelix Fietkau 3c8846e10SFelix Fietkau #include <linux/firmware.h> 4c8846e10SFelix Fietkau #include "mt7603.h" 5c8846e10SFelix Fietkau #include "mcu.h" 6c8846e10SFelix Fietkau #include "eeprom.h" 7c8846e10SFelix Fietkau 8c8846e10SFelix Fietkau #define MCU_SKB_RESERVE 8 9c8846e10SFelix Fietkau 10c8846e10SFelix Fietkau struct mt7603_fw_trailer { 11c8846e10SFelix Fietkau char fw_ver[10]; 12c8846e10SFelix Fietkau char build_date[15]; 13c8846e10SFelix Fietkau __le32 dl_len; 14c8846e10SFelix Fietkau } __packed; 15c8846e10SFelix Fietkau 16c8846e10SFelix Fietkau static int 17114fe5e3SLorenzo Bianconi __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, 18114fe5e3SLorenzo Bianconi int cmd, int *wait_seq) 19c8846e10SFelix Fietkau { 20c8846e10SFelix Fietkau int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12; 21c8846e10SFelix Fietkau struct mt76_dev *mdev = &dev->mt76; 22c8846e10SFelix Fietkau struct mt7603_mcu_txd *txd; 23c8846e10SFelix Fietkau u8 seq; 24c8846e10SFelix Fietkau 2509872957SLorenzo Bianconi seq = ++mdev->mcu.msg_seq & 0xf; 26c8846e10SFelix Fietkau if (!seq) 2709872957SLorenzo Bianconi seq = ++mdev->mcu.msg_seq & 0xf; 28c8846e10SFelix Fietkau 29c8846e10SFelix Fietkau txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen); 30c8846e10SFelix Fietkau memset(txd, 0, hdrlen); 31c8846e10SFelix Fietkau 32c8846e10SFelix Fietkau txd->len = cpu_to_le16(skb->len); 33c8846e10SFelix Fietkau if (cmd == -MCU_CMD_FW_SCATTER) 34c8846e10SFelix Fietkau txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW); 35c8846e10SFelix Fietkau else 36c8846e10SFelix Fietkau txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE); 37c8846e10SFelix Fietkau txd->pkt_type = MCU_PKT_ID; 38c8846e10SFelix Fietkau txd->seq = seq; 39c8846e10SFelix Fietkau 40c8846e10SFelix Fietkau if (cmd < 0) { 41c8846e10SFelix Fietkau txd->cid = -cmd; 42114fe5e3SLorenzo Bianconi txd->set_query = MCU_Q_NA; 43c8846e10SFelix Fietkau } else { 44c8846e10SFelix Fietkau txd->cid = MCU_CMD_EXT_CID; 45c8846e10SFelix Fietkau txd->ext_cid = cmd; 46114fe5e3SLorenzo Bianconi txd->set_query = MCU_Q_SET; 47c8846e10SFelix Fietkau txd->ext_cid_ack = 1; 48c8846e10SFelix Fietkau } 49c8846e10SFelix Fietkau 50c8846e10SFelix Fietkau if (wait_seq) 51c8846e10SFelix Fietkau *wait_seq = seq; 52c8846e10SFelix Fietkau 53c8846e10SFelix Fietkau return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0); 54c8846e10SFelix Fietkau } 55c8846e10SFelix Fietkau 56c8846e10SFelix Fietkau static int 57cc173875SLorenzo Bianconi mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 5811ca82d7SLorenzo Bianconi int len, bool wait_resp) 59c8846e10SFelix Fietkau { 60cc173875SLorenzo Bianconi struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 61c8846e10SFelix Fietkau unsigned long expires = jiffies + 3 * HZ; 62c8846e10SFelix Fietkau struct mt7603_mcu_rxd *rxd; 6311ca82d7SLorenzo Bianconi struct sk_buff *skb; 64c8846e10SFelix Fietkau int ret, seq; 65c8846e10SFelix Fietkau 6611ca82d7SLorenzo Bianconi skb = mt7603_mcu_msg_alloc(data, len); 6711ca82d7SLorenzo Bianconi if (!skb) 6811ca82d7SLorenzo Bianconi return -ENOMEM; 6911ca82d7SLorenzo Bianconi 7009872957SLorenzo Bianconi mutex_lock(&mdev->mcu.mutex); 71c8846e10SFelix Fietkau 72114fe5e3SLorenzo Bianconi ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq); 73c8846e10SFelix Fietkau if (ret) 74c8846e10SFelix Fietkau goto out; 75c8846e10SFelix Fietkau 7611ca82d7SLorenzo Bianconi while (wait_resp) { 77c8846e10SFelix Fietkau bool check_seq = false; 78c8846e10SFelix Fietkau 79c8846e10SFelix Fietkau skb = mt76_mcu_get_response(&dev->mt76, expires); 80c8846e10SFelix Fietkau if (!skb) { 81c8846e10SFelix Fietkau dev_err(mdev->dev, 82c8846e10SFelix Fietkau "MCU message %d (seq %d) timed out\n", 83c8846e10SFelix Fietkau cmd, seq); 84c8846e10SFelix Fietkau dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT; 85c8846e10SFelix Fietkau ret = -ETIMEDOUT; 86c8846e10SFelix Fietkau break; 87c8846e10SFelix Fietkau } 88c8846e10SFelix Fietkau 89c8846e10SFelix Fietkau rxd = (struct mt7603_mcu_rxd *)skb->data; 90c8846e10SFelix Fietkau if (seq == rxd->seq) 91c8846e10SFelix Fietkau check_seq = true; 92c8846e10SFelix Fietkau 93c8846e10SFelix Fietkau dev_kfree_skb(skb); 94c8846e10SFelix Fietkau 95c8846e10SFelix Fietkau if (check_seq) 96c8846e10SFelix Fietkau break; 97c8846e10SFelix Fietkau } 98c8846e10SFelix Fietkau 99c8846e10SFelix Fietkau out: 10009872957SLorenzo Bianconi mutex_unlock(&mdev->mcu.mutex); 101c8846e10SFelix Fietkau 102c8846e10SFelix Fietkau return ret; 103c8846e10SFelix Fietkau } 104c8846e10SFelix Fietkau 105c8846e10SFelix Fietkau static int 106c8846e10SFelix Fietkau mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) 107c8846e10SFelix Fietkau { 108c8846e10SFelix Fietkau struct { 109c8846e10SFelix Fietkau __le32 addr; 110c8846e10SFelix Fietkau __le32 len; 111c8846e10SFelix Fietkau __le32 mode; 112c8846e10SFelix Fietkau } req = { 113c8846e10SFelix Fietkau .addr = cpu_to_le32(addr), 114c8846e10SFelix Fietkau .len = cpu_to_le32(len), 115c8846e10SFelix Fietkau .mode = cpu_to_le32(BIT(31)), 116c8846e10SFelix Fietkau }; 117c8846e10SFelix Fietkau 118cc173875SLorenzo Bianconi return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, 11911ca82d7SLorenzo Bianconi &req, sizeof(req), true); 120c8846e10SFelix Fietkau } 121c8846e10SFelix Fietkau 122c8846e10SFelix Fietkau static int 123c8846e10SFelix Fietkau mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len) 124c8846e10SFelix Fietkau { 125d422bb26SLorenzo Bianconi int cur_len, ret = 0; 126c8846e10SFelix Fietkau 127c8846e10SFelix Fietkau while (len > 0) { 128d422bb26SLorenzo Bianconi cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd), 129c8846e10SFelix Fietkau len); 130c8846e10SFelix Fietkau 131d422bb26SLorenzo Bianconi ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, 132d422bb26SLorenzo Bianconi data, cur_len, false); 133c8846e10SFelix Fietkau if (ret) 134c8846e10SFelix Fietkau break; 135c8846e10SFelix Fietkau 136c8846e10SFelix Fietkau data += cur_len; 137c8846e10SFelix Fietkau len -= cur_len; 138c8846e10SFelix Fietkau } 139c8846e10SFelix Fietkau 140c8846e10SFelix Fietkau return ret; 141c8846e10SFelix Fietkau } 142c8846e10SFelix Fietkau 143c8846e10SFelix Fietkau static int 144c8846e10SFelix Fietkau mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) 145c8846e10SFelix Fietkau { 146c8846e10SFelix Fietkau struct { 147c8846e10SFelix Fietkau __le32 override; 148c8846e10SFelix Fietkau __le32 addr; 149c8846e10SFelix Fietkau } req = { 150c8846e10SFelix Fietkau .override = cpu_to_le32(addr ? 1 : 0), 151c8846e10SFelix Fietkau .addr = cpu_to_le32(addr), 152c8846e10SFelix Fietkau }; 153c8846e10SFelix Fietkau 154cc173875SLorenzo Bianconi return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, 15511ca82d7SLorenzo Bianconi &req, sizeof(req), true); 156c8846e10SFelix Fietkau } 157c8846e10SFelix Fietkau 158c8846e10SFelix Fietkau static int 159a4834814SLorenzo Bianconi mt7603_mcu_restart(struct mt76_dev *dev) 160c8846e10SFelix Fietkau { 161a4834814SLorenzo Bianconi return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, 16211ca82d7SLorenzo Bianconi NULL, 0, true); 163c8846e10SFelix Fietkau } 164c8846e10SFelix Fietkau 165cc173875SLorenzo Bianconi static int mt7603_load_firmware(struct mt7603_dev *dev) 166c8846e10SFelix Fietkau { 167c8846e10SFelix Fietkau const struct firmware *fw; 168c8846e10SFelix Fietkau const struct mt7603_fw_trailer *hdr; 169c8846e10SFelix Fietkau const char *firmware; 170c8846e10SFelix Fietkau int dl_len; 171c8846e10SFelix Fietkau u32 addr, val; 172c8846e10SFelix Fietkau int ret; 173c8846e10SFelix Fietkau 174c8846e10SFelix Fietkau if (is_mt7628(dev)) { 175c8846e10SFelix Fietkau if (mt76xx_rev(dev) == MT7628_REV_E1) 176c8846e10SFelix Fietkau firmware = MT7628_FIRMWARE_E1; 177c8846e10SFelix Fietkau else 178c8846e10SFelix Fietkau firmware = MT7628_FIRMWARE_E2; 179c8846e10SFelix Fietkau } else { 180c8846e10SFelix Fietkau if (mt76xx_rev(dev) < MT7603_REV_E2) 181c8846e10SFelix Fietkau firmware = MT7603_FIRMWARE_E1; 182c8846e10SFelix Fietkau else 183c8846e10SFelix Fietkau firmware = MT7603_FIRMWARE_E2; 184c8846e10SFelix Fietkau } 185c8846e10SFelix Fietkau 186c8846e10SFelix Fietkau ret = request_firmware(&fw, firmware, dev->mt76.dev); 187c8846e10SFelix Fietkau if (ret) 188c8846e10SFelix Fietkau return ret; 189c8846e10SFelix Fietkau 190c8846e10SFelix Fietkau if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 191c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Invalid firmware\n"); 192c8846e10SFelix Fietkau ret = -EINVAL; 193c8846e10SFelix Fietkau goto out; 194c8846e10SFelix Fietkau } 195c8846e10SFelix Fietkau 196c8846e10SFelix Fietkau hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size - 197c8846e10SFelix Fietkau sizeof(*hdr)); 198c8846e10SFelix Fietkau 199c8846e10SFelix Fietkau dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver); 200c8846e10SFelix Fietkau dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date); 201c8846e10SFelix Fietkau 202c8846e10SFelix Fietkau addr = mt7603_reg_map(dev, 0x50012498); 203c8846e10SFelix Fietkau mt76_wr(dev, addr, 0x5); 204c8846e10SFelix Fietkau mt76_wr(dev, addr, 0x5); 205c8846e10SFelix Fietkau udelay(1); 206c8846e10SFelix Fietkau 207c8846e10SFelix Fietkau /* switch to bypass mode */ 208c8846e10SFelix Fietkau mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, 209c8846e10SFelix Fietkau MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5)); 210c8846e10SFelix Fietkau 211c8846e10SFelix Fietkau val = mt76_rr(dev, MT_TOP_MISC2); 212c8846e10SFelix Fietkau if (val & BIT(1)) { 213c8846e10SFelix Fietkau dev_info(dev->mt76.dev, "Firmware already running...\n"); 214c8846e10SFelix Fietkau goto running; 215c8846e10SFelix Fietkau } 216c8846e10SFelix Fietkau 217c8846e10SFelix Fietkau if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) { 218c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n"); 219c8846e10SFelix Fietkau ret = -EIO; 220c8846e10SFelix Fietkau goto out; 221c8846e10SFelix Fietkau } 222c8846e10SFelix Fietkau 223c8846e10SFelix Fietkau dl_len = le32_to_cpu(hdr->dl_len) + 4; 224c8846e10SFelix Fietkau ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); 225c8846e10SFelix Fietkau if (ret) { 226c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Download request failed\n"); 227c8846e10SFelix Fietkau goto out; 228c8846e10SFelix Fietkau } 229c8846e10SFelix Fietkau 230c8846e10SFelix Fietkau ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len); 231c8846e10SFelix Fietkau if (ret) { 232c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); 233c8846e10SFelix Fietkau goto out; 234c8846e10SFelix Fietkau } 235c8846e10SFelix Fietkau 236c8846e10SFelix Fietkau ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); 237c8846e10SFelix Fietkau if (ret) { 238c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Failed to start firmware\n"); 239c8846e10SFelix Fietkau goto out; 240c8846e10SFelix Fietkau } 241c8846e10SFelix Fietkau 242c8846e10SFelix Fietkau if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { 243c8846e10SFelix Fietkau dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); 244c8846e10SFelix Fietkau ret = -EIO; 245c8846e10SFelix Fietkau goto out; 246c8846e10SFelix Fietkau } 247c8846e10SFelix Fietkau 248c8846e10SFelix Fietkau running: 249c8846e10SFelix Fietkau mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); 250c8846e10SFelix Fietkau 251c8846e10SFelix Fietkau mt76_set(dev, MT_SCH_4, BIT(8)); 252c8846e10SFelix Fietkau mt76_clear(dev, MT_SCH_4, BIT(8)); 253c8846e10SFelix Fietkau 254c8846e10SFelix Fietkau dev->mcu_running = true; 2554d0fe26fSLorenzo Bianconi snprintf(dev->mt76.hw->wiphy->fw_version, 2564d0fe26fSLorenzo Bianconi sizeof(dev->mt76.hw->wiphy->fw_version), 2574d0fe26fSLorenzo Bianconi "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 258c8846e10SFelix Fietkau dev_info(dev->mt76.dev, "firmware init done\n"); 259c8846e10SFelix Fietkau 260c8846e10SFelix Fietkau out: 261c8846e10SFelix Fietkau release_firmware(fw); 262c8846e10SFelix Fietkau 263c8846e10SFelix Fietkau return ret; 264c8846e10SFelix Fietkau } 265c8846e10SFelix Fietkau 266cc173875SLorenzo Bianconi int mt7603_mcu_init(struct mt7603_dev *dev) 267cc173875SLorenzo Bianconi { 268cc173875SLorenzo Bianconi static const struct mt76_mcu_ops mt7603_mcu_ops = { 269cc173875SLorenzo Bianconi .mcu_send_msg = mt7603_mcu_msg_send, 270a4834814SLorenzo Bianconi .mcu_restart = mt7603_mcu_restart, 271cc173875SLorenzo Bianconi }; 272cc173875SLorenzo Bianconi 273cc173875SLorenzo Bianconi dev->mt76.mcu_ops = &mt7603_mcu_ops; 274cc173875SLorenzo Bianconi return mt7603_load_firmware(dev); 275cc173875SLorenzo Bianconi } 276cc173875SLorenzo Bianconi 277c8846e10SFelix Fietkau void mt7603_mcu_exit(struct mt7603_dev *dev) 278c8846e10SFelix Fietkau { 279a4834814SLorenzo Bianconi __mt76_mcu_restart(&dev->mt76); 28009872957SLorenzo Bianconi skb_queue_purge(&dev->mt76.mcu.res_q); 281c8846e10SFelix Fietkau } 282c8846e10SFelix Fietkau 283c8846e10SFelix Fietkau int mt7603_mcu_set_eeprom(struct mt7603_dev *dev) 284c8846e10SFelix Fietkau { 285c8846e10SFelix Fietkau static const u16 req_fields[] = { 286c8846e10SFelix Fietkau #define WORD(_start) \ 287c8846e10SFelix Fietkau _start, \ 288c8846e10SFelix Fietkau _start + 1 289c8846e10SFelix Fietkau #define GROUP_2G(_start) \ 290c8846e10SFelix Fietkau WORD(_start), \ 291c8846e10SFelix Fietkau WORD(_start + 2), \ 292c8846e10SFelix Fietkau WORD(_start + 4) 293c8846e10SFelix Fietkau 294c8846e10SFelix Fietkau MT_EE_NIC_CONF_0 + 1, 295c8846e10SFelix Fietkau WORD(MT_EE_NIC_CONF_1), 296c8846e10SFelix Fietkau MT_EE_WIFI_RF_SETTING, 297c8846e10SFelix Fietkau MT_EE_TX_POWER_DELTA_BW40, 298c8846e10SFelix Fietkau MT_EE_TX_POWER_DELTA_BW80 + 1, 299c8846e10SFelix Fietkau MT_EE_TX_POWER_EXT_PA_5G, 300c8846e10SFelix Fietkau MT_EE_TEMP_SENSOR_CAL, 301c8846e10SFelix Fietkau GROUP_2G(MT_EE_TX_POWER_0_START_2G), 302c8846e10SFelix Fietkau GROUP_2G(MT_EE_TX_POWER_1_START_2G), 303c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_CCK), 304c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_OFDM_2G_6M), 305c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_OFDM_2G_24M), 306c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_OFDM_2G_54M), 307c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_HT_BPSK_QPSK), 308c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_HT_16_64_QAM), 309c8846e10SFelix Fietkau WORD(MT_EE_TX_POWER_HT_64_QAM), 310c8846e10SFelix Fietkau MT_EE_ELAN_RX_MODE_GAIN, 311c8846e10SFelix Fietkau MT_EE_ELAN_RX_MODE_NF, 312c8846e10SFelix Fietkau MT_EE_ELAN_RX_MODE_P1DB, 313c8846e10SFelix Fietkau MT_EE_ELAN_BYPASS_MODE_GAIN, 314c8846e10SFelix Fietkau MT_EE_ELAN_BYPASS_MODE_NF, 315c8846e10SFelix Fietkau MT_EE_ELAN_BYPASS_MODE_P1DB, 316c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_NEG_6_7), 317c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_NEG_4_5), 318c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_NEG_2_3), 319c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_NEG_0_1), 320c8846e10SFelix Fietkau WORD(MT_EE_REF_STEP_24G), 321c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_PLUS_1_2), 322c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_PLUS_3_4), 323c8846e10SFelix Fietkau WORD(MT_EE_STEP_NUM_PLUS_5_6), 324c8846e10SFelix Fietkau MT_EE_STEP_NUM_PLUS_7, 325c8846e10SFelix Fietkau MT_EE_XTAL_FREQ_OFFSET, 326c8846e10SFelix Fietkau MT_EE_XTAL_TRIM_2_COMP, 327c8846e10SFelix Fietkau MT_EE_XTAL_TRIM_3_COMP, 328c8846e10SFelix Fietkau MT_EE_XTAL_WF_RFCAL, 329c8846e10SFelix Fietkau 330c8846e10SFelix Fietkau /* unknown fields below */ 331c8846e10SFelix Fietkau WORD(0x24), 332c8846e10SFelix Fietkau 0x34, 333c8846e10SFelix Fietkau 0x39, 334c8846e10SFelix Fietkau 0x3b, 335c8846e10SFelix Fietkau WORD(0x42), 336c8846e10SFelix Fietkau WORD(0x9e), 337c8846e10SFelix Fietkau 0xf2, 338c8846e10SFelix Fietkau WORD(0xf8), 339c8846e10SFelix Fietkau 0xfa, 340c8846e10SFelix Fietkau 0x12e, 341c8846e10SFelix Fietkau WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136), 342c8846e10SFelix Fietkau WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e), 343c8846e10SFelix Fietkau 344c8846e10SFelix Fietkau #undef GROUP_2G 345c8846e10SFelix Fietkau #undef WORD 346c8846e10SFelix Fietkau 347c8846e10SFelix Fietkau }; 348c8846e10SFelix Fietkau struct req_data { 349676fabd1SLorenzo Bianconi __le16 addr; 350c8846e10SFelix Fietkau u8 val; 351c8846e10SFelix Fietkau u8 pad; 352c8846e10SFelix Fietkau } __packed; 353c8846e10SFelix Fietkau struct { 354c8846e10SFelix Fietkau u8 buffer_mode; 355c8846e10SFelix Fietkau u8 len; 356c8846e10SFelix Fietkau u8 pad[2]; 3574d2a6f7bSLorenzo Bianconi } req_hdr = { 358c8846e10SFelix Fietkau .buffer_mode = 1, 359c8846e10SFelix Fietkau .len = ARRAY_SIZE(req_fields) - 1, 360c8846e10SFelix Fietkau }; 3614d2a6f7bSLorenzo Bianconi const int size = 0xff * sizeof(struct req_data); 3624d2a6f7bSLorenzo Bianconi u8 *req, *eep = (u8 *)dev->mt76.eeprom.data; 3634d2a6f7bSLorenzo Bianconi int i, ret, len = sizeof(req_hdr) + size; 3644d2a6f7bSLorenzo Bianconi struct req_data *data; 365c8846e10SFelix Fietkau 3664d2a6f7bSLorenzo Bianconi BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size); 367c8846e10SFelix Fietkau 3684d2a6f7bSLorenzo Bianconi req = kmalloc(len, GFP_KERNEL); 3694d2a6f7bSLorenzo Bianconi if (!req) 3704d2a6f7bSLorenzo Bianconi return -ENOMEM; 3714d2a6f7bSLorenzo Bianconi 3724d2a6f7bSLorenzo Bianconi memcpy(req, &req_hdr, sizeof(req_hdr)); 3734d2a6f7bSLorenzo Bianconi data = (struct req_data *)(req + sizeof(req_hdr)); 3744d2a6f7bSLorenzo Bianconi memset(data, 0, size); 375c8846e10SFelix Fietkau for (i = 0; i < ARRAY_SIZE(req_fields); i++) { 3764d2a6f7bSLorenzo Bianconi data[i].addr = cpu_to_le16(req_fields[i]); 3774d2a6f7bSLorenzo Bianconi data[i].val = eep[req_fields[i]]; 378c8846e10SFelix Fietkau } 379c8846e10SFelix Fietkau 3804d2a6f7bSLorenzo Bianconi ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 3814d2a6f7bSLorenzo Bianconi req, len, true); 3824d2a6f7bSLorenzo Bianconi kfree(req); 3834d2a6f7bSLorenzo Bianconi 3844d2a6f7bSLorenzo Bianconi return ret; 385c8846e10SFelix Fietkau } 386c8846e10SFelix Fietkau 387c8846e10SFelix Fietkau static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev) 388c8846e10SFelix Fietkau { 389c8846e10SFelix Fietkau struct { 390c8846e10SFelix Fietkau u8 center_channel; 391c8846e10SFelix Fietkau u8 tssi; 392c8846e10SFelix Fietkau u8 temp_comp; 393c8846e10SFelix Fietkau u8 target_power[2]; 394c8846e10SFelix Fietkau u8 rate_power_delta[14]; 395c8846e10SFelix Fietkau u8 bw_power_delta; 396c8846e10SFelix Fietkau u8 ch_power_delta[6]; 397c8846e10SFelix Fietkau u8 temp_comp_power[17]; 398c8846e10SFelix Fietkau u8 reserved; 399c8846e10SFelix Fietkau } req = { 40096747a51SFelix Fietkau .center_channel = dev->mphy.chandef.chan->hw_value, 401c8846e10SFelix Fietkau #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n] 402c8846e10SFelix Fietkau .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1), 403c8846e10SFelix Fietkau .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1), 404c8846e10SFelix Fietkau .target_power = { 405c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2), 406c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2) 407c8846e10SFelix Fietkau }, 408c8846e10SFelix Fietkau .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40), 409c8846e10SFelix Fietkau .ch_power_delta = { 410c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3), 411c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4), 412c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5), 413c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3), 414c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4), 415c8846e10SFelix Fietkau EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5) 416c8846e10SFelix Fietkau }, 417c8846e10SFelix Fietkau #undef EEP_VAL 418c8846e10SFelix Fietkau }; 419c8846e10SFelix Fietkau u8 *eep = (u8 *)dev->mt76.eeprom.data; 420c8846e10SFelix Fietkau 421c8846e10SFelix Fietkau memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK, 422c8846e10SFelix Fietkau sizeof(req.rate_power_delta)); 423c8846e10SFelix Fietkau 424c8846e10SFelix Fietkau memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7, 425c8846e10SFelix Fietkau sizeof(req.temp_comp_power)); 426c8846e10SFelix Fietkau 427cc173875SLorenzo Bianconi return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL, 42811ca82d7SLorenzo Bianconi &req, sizeof(req), true); 429c8846e10SFelix Fietkau } 430c8846e10SFelix Fietkau 431c8846e10SFelix Fietkau int mt7603_mcu_set_channel(struct mt7603_dev *dev) 432c8846e10SFelix Fietkau { 43396747a51SFelix Fietkau struct cfg80211_chan_def *chandef = &dev->mphy.chandef; 434c8846e10SFelix Fietkau struct ieee80211_hw *hw = mt76_hw(dev); 435beaaeb6bSFelix Fietkau int n_chains = hweight8(dev->mphy.antenna_mask); 436c8846e10SFelix Fietkau struct { 437c8846e10SFelix Fietkau u8 control_chan; 438c8846e10SFelix Fietkau u8 center_chan; 439c8846e10SFelix Fietkau u8 bw; 440c8846e10SFelix Fietkau u8 tx_streams; 441c8846e10SFelix Fietkau u8 rx_streams; 442c8846e10SFelix Fietkau u8 _res0[7]; 443c8846e10SFelix Fietkau u8 txpower[21]; 444c8846e10SFelix Fietkau u8 _res1[3]; 445c8846e10SFelix Fietkau } req = { 446c8846e10SFelix Fietkau .control_chan = chandef->chan->hw_value, 447c8846e10SFelix Fietkau .center_chan = chandef->chan->hw_value, 448c8846e10SFelix Fietkau .bw = MT_BW_20, 449c8846e10SFelix Fietkau .tx_streams = n_chains, 450c8846e10SFelix Fietkau .rx_streams = n_chains, 451c8846e10SFelix Fietkau }; 452c8846e10SFelix Fietkau s8 tx_power; 45311ca82d7SLorenzo Bianconi int i, ret; 454c8846e10SFelix Fietkau 45596747a51SFelix Fietkau if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) { 456c8846e10SFelix Fietkau req.bw = MT_BW_40; 457c8846e10SFelix Fietkau if (chandef->center_freq1 > chandef->chan->center_freq) 458c8846e10SFelix Fietkau req.center_chan += 2; 459c8846e10SFelix Fietkau else 460c8846e10SFelix Fietkau req.center_chan -= 2; 461c8846e10SFelix Fietkau } 462c8846e10SFelix Fietkau 463c8846e10SFelix Fietkau tx_power = hw->conf.power_level * 2; 464beaaeb6bSFelix Fietkau if (dev->mphy.antenna_mask == 3) 465c8846e10SFelix Fietkau tx_power -= 6; 466c8846e10SFelix Fietkau tx_power = min(tx_power, dev->tx_power_limit); 467c8846e10SFelix Fietkau 468beaaeb6bSFelix Fietkau dev->mphy.txpower_cur = tx_power; 469c8846e10SFelix Fietkau 470c8846e10SFelix Fietkau for (i = 0; i < ARRAY_SIZE(req.txpower); i++) 471c8846e10SFelix Fietkau req.txpower[i] = tx_power; 472c8846e10SFelix Fietkau 473cc173875SLorenzo Bianconi ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, 47411ca82d7SLorenzo Bianconi &req, sizeof(req), true); 475c8846e10SFelix Fietkau if (ret) 476c8846e10SFelix Fietkau return ret; 477c8846e10SFelix Fietkau 478c8846e10SFelix Fietkau return mt7603_mcu_set_tx_power(dev); 479c8846e10SFelix Fietkau } 480