18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/firmware.h> 48c2ecf20Sopenharmony_ci#include "mt7603.h" 58c2ecf20Sopenharmony_ci#include "mcu.h" 68c2ecf20Sopenharmony_ci#include "eeprom.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define MCU_SKB_RESERVE 8 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct mt7603_fw_trailer { 118c2ecf20Sopenharmony_ci char fw_ver[10]; 128c2ecf20Sopenharmony_ci char build_date[15]; 138c2ecf20Sopenharmony_ci __le32 dl_len; 148c2ecf20Sopenharmony_ci} __packed; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int 178c2ecf20Sopenharmony_ci__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, 188c2ecf20Sopenharmony_ci int cmd, int *wait_seq) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12; 218c2ecf20Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 228c2ecf20Sopenharmony_ci struct mt7603_mcu_txd *txd; 238c2ecf20Sopenharmony_ci u8 seq; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci seq = ++mdev->mcu.msg_seq & 0xf; 268c2ecf20Sopenharmony_ci if (!seq) 278c2ecf20Sopenharmony_ci seq = ++mdev->mcu.msg_seq & 0xf; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci txd->len = cpu_to_le16(skb->len); 328c2ecf20Sopenharmony_ci if (cmd == -MCU_CMD_FW_SCATTER) 338c2ecf20Sopenharmony_ci txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW); 348c2ecf20Sopenharmony_ci else 358c2ecf20Sopenharmony_ci txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE); 368c2ecf20Sopenharmony_ci txd->pkt_type = MCU_PKT_ID; 378c2ecf20Sopenharmony_ci txd->seq = seq; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (cmd < 0) { 408c2ecf20Sopenharmony_ci txd->cid = -cmd; 418c2ecf20Sopenharmony_ci txd->set_query = MCU_Q_NA; 428c2ecf20Sopenharmony_ci } else { 438c2ecf20Sopenharmony_ci txd->cid = MCU_CMD_EXT_CID; 448c2ecf20Sopenharmony_ci txd->ext_cid = cmd; 458c2ecf20Sopenharmony_ci txd->set_query = MCU_Q_SET; 468c2ecf20Sopenharmony_ci txd->ext_cid_ack = 1; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (wait_seq) 508c2ecf20Sopenharmony_ci *wait_seq = seq; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int 568c2ecf20Sopenharmony_cimt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, 578c2ecf20Sopenharmony_ci int len, bool wait_resp) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 608c2ecf20Sopenharmony_ci unsigned long expires = jiffies + 3 * HZ; 618c2ecf20Sopenharmony_ci struct mt7603_mcu_rxd *rxd; 628c2ecf20Sopenharmony_ci struct sk_buff *skb; 638c2ecf20Sopenharmony_ci int ret, seq; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci skb = mt76_mcu_msg_alloc(mdev, data, len); 668c2ecf20Sopenharmony_ci if (!skb) 678c2ecf20Sopenharmony_ci return -ENOMEM; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci mutex_lock(&mdev->mcu.mutex); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq); 728c2ecf20Sopenharmony_ci if (ret) 738c2ecf20Sopenharmony_ci goto out; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci while (wait_resp) { 768c2ecf20Sopenharmony_ci bool check_seq = false; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci skb = mt76_mcu_get_response(&dev->mt76, expires); 798c2ecf20Sopenharmony_ci if (!skb) { 808c2ecf20Sopenharmony_ci dev_err(mdev->dev, 818c2ecf20Sopenharmony_ci "MCU message %d (seq %d) timed out\n", 828c2ecf20Sopenharmony_ci cmd, seq); 838c2ecf20Sopenharmony_ci dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT; 848c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci rxd = (struct mt7603_mcu_rxd *)skb->data; 898c2ecf20Sopenharmony_ci if (seq == rxd->seq) 908c2ecf20Sopenharmony_ci check_seq = true; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (check_seq) 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciout: 998c2ecf20Sopenharmony_ci mutex_unlock(&mdev->mcu.mutex); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int 1058c2ecf20Sopenharmony_cimt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct { 1088c2ecf20Sopenharmony_ci __le32 addr; 1098c2ecf20Sopenharmony_ci __le32 len; 1108c2ecf20Sopenharmony_ci __le32 mode; 1118c2ecf20Sopenharmony_ci } req = { 1128c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 1138c2ecf20Sopenharmony_ci .len = cpu_to_le32(len), 1148c2ecf20Sopenharmony_ci .mode = cpu_to_le32(BIT(31)), 1158c2ecf20Sopenharmony_ci }; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, 1188c2ecf20Sopenharmony_ci &req, sizeof(req), true); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int 1228c2ecf20Sopenharmony_cimt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int cur_len, ret = 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci while (len > 0) { 1278c2ecf20Sopenharmony_ci cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd), 1288c2ecf20Sopenharmony_ci len); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, 1318c2ecf20Sopenharmony_ci data, cur_len, false); 1328c2ecf20Sopenharmony_ci if (ret) 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci data += cur_len; 1368c2ecf20Sopenharmony_ci len -= cur_len; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int 1438c2ecf20Sopenharmony_cimt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct { 1468c2ecf20Sopenharmony_ci __le32 override; 1478c2ecf20Sopenharmony_ci __le32 addr; 1488c2ecf20Sopenharmony_ci } req = { 1498c2ecf20Sopenharmony_ci .override = cpu_to_le32(addr ? 1 : 0), 1508c2ecf20Sopenharmony_ci .addr = cpu_to_le32(addr), 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, 1548c2ecf20Sopenharmony_ci &req, sizeof(req), true); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int 1588c2ecf20Sopenharmony_cimt7603_mcu_restart(struct mt76_dev *dev) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, 1618c2ecf20Sopenharmony_ci NULL, 0, true); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int mt7603_load_firmware(struct mt7603_dev *dev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci const struct firmware *fw; 1678c2ecf20Sopenharmony_ci const struct mt7603_fw_trailer *hdr; 1688c2ecf20Sopenharmony_ci const char *firmware; 1698c2ecf20Sopenharmony_ci int dl_len; 1708c2ecf20Sopenharmony_ci u32 addr, val; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (is_mt7628(dev)) { 1748c2ecf20Sopenharmony_ci if (mt76xx_rev(dev) == MT7628_REV_E1) 1758c2ecf20Sopenharmony_ci firmware = MT7628_FIRMWARE_E1; 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci firmware = MT7628_FIRMWARE_E2; 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci if (mt76xx_rev(dev) < MT7603_REV_E2) 1808c2ecf20Sopenharmony_ci firmware = MT7603_FIRMWARE_E1; 1818c2ecf20Sopenharmony_ci else 1828c2ecf20Sopenharmony_ci firmware = MT7603_FIRMWARE_E2; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = request_firmware(&fw, firmware, dev->mt76.dev); 1868c2ecf20Sopenharmony_ci if (ret) 1878c2ecf20Sopenharmony_ci return ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 1908c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 1918c2ecf20Sopenharmony_ci ret = -EINVAL; 1928c2ecf20Sopenharmony_ci goto out; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size - 1968c2ecf20Sopenharmony_ci sizeof(*hdr)); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver); 1998c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci addr = mt7603_reg_map(dev, 0x50012498); 2028c2ecf20Sopenharmony_ci mt76_wr(dev, addr, 0x5); 2038c2ecf20Sopenharmony_ci mt76_wr(dev, addr, 0x5); 2048c2ecf20Sopenharmony_ci udelay(1); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* switch to bypass mode */ 2078c2ecf20Sopenharmony_ci mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, 2088c2ecf20Sopenharmony_ci MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_TOP_MISC2); 2118c2ecf20Sopenharmony_ci if (val & BIT(1)) { 2128c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "Firmware already running...\n"); 2138c2ecf20Sopenharmony_ci goto running; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) { 2178c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n"); 2188c2ecf20Sopenharmony_ci ret = -EIO; 2198c2ecf20Sopenharmony_ci goto out; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci dl_len = le32_to_cpu(hdr->dl_len) + 4; 2238c2ecf20Sopenharmony_ci ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 2268c2ecf20Sopenharmony_ci goto out; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len); 2308c2ecf20Sopenharmony_ci if (ret) { 2318c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); 2368c2ecf20Sopenharmony_ci if (ret) { 2378c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start firmware\n"); 2388c2ecf20Sopenharmony_ci goto out; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { 2428c2ecf20Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); 2438c2ecf20Sopenharmony_ci ret = -EIO; 2448c2ecf20Sopenharmony_ci goto out; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cirunning: 2488c2ecf20Sopenharmony_ci mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci mt76_set(dev, MT_SCH_4, BIT(8)); 2518c2ecf20Sopenharmony_ci mt76_clear(dev, MT_SCH_4, BIT(8)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci dev->mcu_running = true; 2548c2ecf20Sopenharmony_ci snprintf(dev->mt76.hw->wiphy->fw_version, 2558c2ecf20Sopenharmony_ci sizeof(dev->mt76.hw->wiphy->fw_version), 2568c2ecf20Sopenharmony_ci "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 2578c2ecf20Sopenharmony_ci dev_info(dev->mt76.dev, "firmware init done\n"); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ciout: 2608c2ecf20Sopenharmony_ci release_firmware(fw); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return ret; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciint mt7603_mcu_init(struct mt7603_dev *dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci static const struct mt76_mcu_ops mt7603_mcu_ops = { 2688c2ecf20Sopenharmony_ci .headroom = sizeof(struct mt7603_mcu_txd), 2698c2ecf20Sopenharmony_ci .mcu_send_msg = mt7603_mcu_msg_send, 2708c2ecf20Sopenharmony_ci .mcu_restart = mt7603_mcu_restart, 2718c2ecf20Sopenharmony_ci }; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci dev->mt76.mcu_ops = &mt7603_mcu_ops; 2748c2ecf20Sopenharmony_ci return mt7603_load_firmware(dev); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_civoid mt7603_mcu_exit(struct mt7603_dev *dev) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci __mt76_mcu_restart(&dev->mt76); 2808c2ecf20Sopenharmony_ci skb_queue_purge(&dev->mt76.mcu.res_q); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciint mt7603_mcu_set_eeprom(struct mt7603_dev *dev) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci static const u16 req_fields[] = { 2868c2ecf20Sopenharmony_ci#define WORD(_start) \ 2878c2ecf20Sopenharmony_ci _start, \ 2888c2ecf20Sopenharmony_ci _start + 1 2898c2ecf20Sopenharmony_ci#define GROUP_2G(_start) \ 2908c2ecf20Sopenharmony_ci WORD(_start), \ 2918c2ecf20Sopenharmony_ci WORD(_start + 2), \ 2928c2ecf20Sopenharmony_ci WORD(_start + 4) 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci MT_EE_NIC_CONF_0 + 1, 2958c2ecf20Sopenharmony_ci WORD(MT_EE_NIC_CONF_1), 2968c2ecf20Sopenharmony_ci MT_EE_WIFI_RF_SETTING, 2978c2ecf20Sopenharmony_ci MT_EE_TX_POWER_DELTA_BW40, 2988c2ecf20Sopenharmony_ci MT_EE_TX_POWER_DELTA_BW80 + 1, 2998c2ecf20Sopenharmony_ci MT_EE_TX_POWER_EXT_PA_5G, 3008c2ecf20Sopenharmony_ci MT_EE_TEMP_SENSOR_CAL, 3018c2ecf20Sopenharmony_ci GROUP_2G(MT_EE_TX_POWER_0_START_2G), 3028c2ecf20Sopenharmony_ci GROUP_2G(MT_EE_TX_POWER_1_START_2G), 3038c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_CCK), 3048c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_6M), 3058c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_24M), 3068c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_54M), 3078c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_BPSK_QPSK), 3088c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_16_64_QAM), 3098c2ecf20Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_64_QAM), 3108c2ecf20Sopenharmony_ci MT_EE_ELAN_RX_MODE_GAIN, 3118c2ecf20Sopenharmony_ci MT_EE_ELAN_RX_MODE_NF, 3128c2ecf20Sopenharmony_ci MT_EE_ELAN_RX_MODE_P1DB, 3138c2ecf20Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_GAIN, 3148c2ecf20Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_NF, 3158c2ecf20Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_P1DB, 3168c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_6_7), 3178c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_4_5), 3188c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_2_3), 3198c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_0_1), 3208c2ecf20Sopenharmony_ci WORD(MT_EE_REF_STEP_24G), 3218c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_1_2), 3228c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_3_4), 3238c2ecf20Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_5_6), 3248c2ecf20Sopenharmony_ci MT_EE_STEP_NUM_PLUS_7, 3258c2ecf20Sopenharmony_ci MT_EE_XTAL_FREQ_OFFSET, 3268c2ecf20Sopenharmony_ci MT_EE_XTAL_TRIM_2_COMP, 3278c2ecf20Sopenharmony_ci MT_EE_XTAL_TRIM_3_COMP, 3288c2ecf20Sopenharmony_ci MT_EE_XTAL_WF_RFCAL, 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* unknown fields below */ 3318c2ecf20Sopenharmony_ci WORD(0x24), 3328c2ecf20Sopenharmony_ci 0x34, 3338c2ecf20Sopenharmony_ci 0x39, 3348c2ecf20Sopenharmony_ci 0x3b, 3358c2ecf20Sopenharmony_ci WORD(0x42), 3368c2ecf20Sopenharmony_ci WORD(0x9e), 3378c2ecf20Sopenharmony_ci 0xf2, 3388c2ecf20Sopenharmony_ci WORD(0xf8), 3398c2ecf20Sopenharmony_ci 0xfa, 3408c2ecf20Sopenharmony_ci 0x12e, 3418c2ecf20Sopenharmony_ci WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136), 3428c2ecf20Sopenharmony_ci WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e), 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci#undef GROUP_2G 3458c2ecf20Sopenharmony_ci#undef WORD 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci }; 3488c2ecf20Sopenharmony_ci struct req_data { 3498c2ecf20Sopenharmony_ci __le16 addr; 3508c2ecf20Sopenharmony_ci u8 val; 3518c2ecf20Sopenharmony_ci u8 pad; 3528c2ecf20Sopenharmony_ci } __packed; 3538c2ecf20Sopenharmony_ci struct { 3548c2ecf20Sopenharmony_ci u8 buffer_mode; 3558c2ecf20Sopenharmony_ci u8 len; 3568c2ecf20Sopenharmony_ci u8 pad[2]; 3578c2ecf20Sopenharmony_ci } req_hdr = { 3588c2ecf20Sopenharmony_ci .buffer_mode = 1, 3598c2ecf20Sopenharmony_ci .len = ARRAY_SIZE(req_fields) - 1, 3608c2ecf20Sopenharmony_ci }; 3618c2ecf20Sopenharmony_ci const int size = 0xff * sizeof(struct req_data); 3628c2ecf20Sopenharmony_ci u8 *req, *eep = (u8 *)dev->mt76.eeprom.data; 3638c2ecf20Sopenharmony_ci int i, ret, len = sizeof(req_hdr) + size; 3648c2ecf20Sopenharmony_ci struct req_data *data; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci req = kmalloc(len, GFP_KERNEL); 3698c2ecf20Sopenharmony_ci if (!req) 3708c2ecf20Sopenharmony_ci return -ENOMEM; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci memcpy(req, &req_hdr, sizeof(req_hdr)); 3738c2ecf20Sopenharmony_ci data = (struct req_data *)(req + sizeof(req_hdr)); 3748c2ecf20Sopenharmony_ci memset(data, 0, size); 3758c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req_fields); i++) { 3768c2ecf20Sopenharmony_ci data[i].addr = cpu_to_le16(req_fields[i]); 3778c2ecf20Sopenharmony_ci data[i].val = eep[req_fields[i]]; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 3818c2ecf20Sopenharmony_ci req, len, true); 3828c2ecf20Sopenharmony_ci kfree(req); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int mt7603_mcu_set_tx_power(struct mt7603_dev *dev) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct { 3908c2ecf20Sopenharmony_ci u8 center_channel; 3918c2ecf20Sopenharmony_ci u8 tssi; 3928c2ecf20Sopenharmony_ci u8 temp_comp; 3938c2ecf20Sopenharmony_ci u8 target_power[2]; 3948c2ecf20Sopenharmony_ci u8 rate_power_delta[14]; 3958c2ecf20Sopenharmony_ci u8 bw_power_delta; 3968c2ecf20Sopenharmony_ci u8 ch_power_delta[6]; 3978c2ecf20Sopenharmony_ci u8 temp_comp_power[17]; 3988c2ecf20Sopenharmony_ci u8 reserved; 3998c2ecf20Sopenharmony_ci } req = { 4008c2ecf20Sopenharmony_ci .center_channel = dev->mphy.chandef.chan->hw_value, 4018c2ecf20Sopenharmony_ci#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n] 4028c2ecf20Sopenharmony_ci .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1), 4038c2ecf20Sopenharmony_ci .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1), 4048c2ecf20Sopenharmony_ci .target_power = { 4058c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2), 4068c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2) 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40), 4098c2ecf20Sopenharmony_ci .ch_power_delta = { 4108c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3), 4118c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4), 4128c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5), 4138c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3), 4148c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4), 4158c2ecf20Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5) 4168c2ecf20Sopenharmony_ci }, 4178c2ecf20Sopenharmony_ci#undef EEP_VAL 4188c2ecf20Sopenharmony_ci }; 4198c2ecf20Sopenharmony_ci u8 *eep = (u8 *)dev->mt76.eeprom.data; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK, 4228c2ecf20Sopenharmony_ci sizeof(req.rate_power_delta)); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7, 4258c2ecf20Sopenharmony_ci sizeof(req.temp_comp_power)); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL, 4288c2ecf20Sopenharmony_ci &req, sizeof(req), true); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciint mt7603_mcu_set_channel(struct mt7603_dev *dev) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &dev->mphy.chandef; 4348c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = mt76_hw(dev); 4358c2ecf20Sopenharmony_ci int n_chains = hweight8(dev->mphy.antenna_mask); 4368c2ecf20Sopenharmony_ci struct { 4378c2ecf20Sopenharmony_ci u8 control_chan; 4388c2ecf20Sopenharmony_ci u8 center_chan; 4398c2ecf20Sopenharmony_ci u8 bw; 4408c2ecf20Sopenharmony_ci u8 tx_streams; 4418c2ecf20Sopenharmony_ci u8 rx_streams; 4428c2ecf20Sopenharmony_ci u8 _res0[7]; 4438c2ecf20Sopenharmony_ci u8 txpower[21]; 4448c2ecf20Sopenharmony_ci u8 _res1[3]; 4458c2ecf20Sopenharmony_ci } req = { 4468c2ecf20Sopenharmony_ci .control_chan = chandef->chan->hw_value, 4478c2ecf20Sopenharmony_ci .center_chan = chandef->chan->hw_value, 4488c2ecf20Sopenharmony_ci .bw = MT_BW_20, 4498c2ecf20Sopenharmony_ci .tx_streams = n_chains, 4508c2ecf20Sopenharmony_ci .rx_streams = n_chains, 4518c2ecf20Sopenharmony_ci }; 4528c2ecf20Sopenharmony_ci s8 tx_power; 4538c2ecf20Sopenharmony_ci int i, ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) { 4568c2ecf20Sopenharmony_ci req.bw = MT_BW_40; 4578c2ecf20Sopenharmony_ci if (chandef->center_freq1 > chandef->chan->center_freq) 4588c2ecf20Sopenharmony_ci req.center_chan += 2; 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci req.center_chan -= 2; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci tx_power = hw->conf.power_level * 2; 4648c2ecf20Sopenharmony_ci if (dev->mphy.antenna_mask == 3) 4658c2ecf20Sopenharmony_ci tx_power -= 6; 4668c2ecf20Sopenharmony_ci tx_power = min(tx_power, dev->tx_power_limit); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci dev->mphy.txpower_cur = tx_power; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req.txpower); i++) 4718c2ecf20Sopenharmony_ci req.txpower[i] = tx_power; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, 4748c2ecf20Sopenharmony_ci &req, sizeof(req), true); 4758c2ecf20Sopenharmony_ci if (ret) 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return mt7603_mcu_set_tx_power(dev); 4798c2ecf20Sopenharmony_ci} 480