162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/firmware.h> 462306a36Sopenharmony_ci#include "mt7603.h" 562306a36Sopenharmony_ci#include "mcu.h" 662306a36Sopenharmony_ci#include "eeprom.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define MCU_SKB_RESERVE 8 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistruct mt7603_fw_trailer { 1162306a36Sopenharmony_ci char fw_ver[10]; 1262306a36Sopenharmony_ci char build_date[15]; 1362306a36Sopenharmony_ci __le32 dl_len; 1462306a36Sopenharmony_ci} __packed; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int 1762306a36Sopenharmony_cimt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd, 1862306a36Sopenharmony_ci struct sk_buff *skb, int seq) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 2162306a36Sopenharmony_ci struct mt7603_mcu_rxd *rxd; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (!skb) { 2462306a36Sopenharmony_ci dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n", 2562306a36Sopenharmony_ci abs(cmd), seq); 2662306a36Sopenharmony_ci dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT; 2762306a36Sopenharmony_ci return -ETIMEDOUT; 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci rxd = (struct mt7603_mcu_rxd *)skb->data; 3162306a36Sopenharmony_ci if (seq != rxd->seq) 3262306a36Sopenharmony_ci return -EAGAIN; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int 3862306a36Sopenharmony_cimt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb, 3962306a36Sopenharmony_ci int cmd, int *wait_seq) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 4262306a36Sopenharmony_ci int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12; 4362306a36Sopenharmony_ci struct mt7603_mcu_txd *txd; 4462306a36Sopenharmony_ci u8 seq; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci mdev->mcu.timeout = 3 * HZ; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci seq = ++mdev->mcu.msg_seq & 0xf; 4962306a36Sopenharmony_ci if (!seq) 5062306a36Sopenharmony_ci seq = ++mdev->mcu.msg_seq & 0xf; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci txd->len = cpu_to_le16(skb->len); 5562306a36Sopenharmony_ci if (cmd == -MCU_CMD_FW_SCATTER) 5662306a36Sopenharmony_ci txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW); 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE); 5962306a36Sopenharmony_ci txd->pkt_type = MCU_PKT_ID; 6062306a36Sopenharmony_ci txd->seq = seq; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (cmd < 0) { 6362306a36Sopenharmony_ci txd->cid = -cmd; 6462306a36Sopenharmony_ci txd->set_query = MCU_Q_NA; 6562306a36Sopenharmony_ci } else { 6662306a36Sopenharmony_ci txd->cid = MCU_CMD_EXT_CID; 6762306a36Sopenharmony_ci txd->ext_cid = cmd; 6862306a36Sopenharmony_ci txd->set_query = MCU_Q_SET; 6962306a36Sopenharmony_ci txd->ext_cid_ack = 1; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (wait_seq) 7362306a36Sopenharmony_ci *wait_seq = seq; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int 7962306a36Sopenharmony_cimt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct { 8262306a36Sopenharmony_ci __le32 addr; 8362306a36Sopenharmony_ci __le32 len; 8462306a36Sopenharmony_ci __le32 mode; 8562306a36Sopenharmony_ci } req = { 8662306a36Sopenharmony_ci .addr = cpu_to_le32(addr), 8762306a36Sopenharmony_ci .len = cpu_to_le32(len), 8862306a36Sopenharmony_ci .mode = cpu_to_le32(BIT(31)), 8962306a36Sopenharmony_ci }; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, 9262306a36Sopenharmony_ci &req, sizeof(req), true); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int 9662306a36Sopenharmony_cimt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct { 9962306a36Sopenharmony_ci __le32 override; 10062306a36Sopenharmony_ci __le32 addr; 10162306a36Sopenharmony_ci } req = { 10262306a36Sopenharmony_ci .override = cpu_to_le32(addr ? 1 : 0), 10362306a36Sopenharmony_ci .addr = cpu_to_le32(addr), 10462306a36Sopenharmony_ci }; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req, 10762306a36Sopenharmony_ci sizeof(req), true); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int 11162306a36Sopenharmony_cimt7603_mcu_restart(struct mt76_dev *dev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int mt7603_load_firmware(struct mt7603_dev *dev) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci const struct firmware *fw; 11962306a36Sopenharmony_ci const struct mt7603_fw_trailer *hdr; 12062306a36Sopenharmony_ci const char *firmware; 12162306a36Sopenharmony_ci int dl_len; 12262306a36Sopenharmony_ci u32 addr, val; 12362306a36Sopenharmony_ci int ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (is_mt7628(dev)) { 12662306a36Sopenharmony_ci if (mt76xx_rev(dev) == MT7628_REV_E1) 12762306a36Sopenharmony_ci firmware = MT7628_FIRMWARE_E1; 12862306a36Sopenharmony_ci else 12962306a36Sopenharmony_ci firmware = MT7628_FIRMWARE_E2; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci if (mt76xx_rev(dev) < MT7603_REV_E2) 13262306a36Sopenharmony_ci firmware = MT7603_FIRMWARE_E1; 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci firmware = MT7603_FIRMWARE_E2; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ret = request_firmware(&fw, firmware, dev->mt76.dev); 13862306a36Sopenharmony_ci if (ret) 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 14262306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Invalid firmware\n"); 14362306a36Sopenharmony_ci ret = -EINVAL; 14462306a36Sopenharmony_ci goto out; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size - 14862306a36Sopenharmony_ci sizeof(*hdr)); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver); 15162306a36Sopenharmony_ci dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci addr = mt7603_reg_map(dev, 0x50012498); 15462306a36Sopenharmony_ci mt76_wr(dev, addr, 0x5); 15562306a36Sopenharmony_ci mt76_wr(dev, addr, 0x5); 15662306a36Sopenharmony_ci udelay(1); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* switch to bypass mode */ 15962306a36Sopenharmony_ci mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, 16062306a36Sopenharmony_ci MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5)); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci val = mt76_rr(dev, MT_TOP_MISC2); 16362306a36Sopenharmony_ci if (val & BIT(1)) { 16462306a36Sopenharmony_ci dev_info(dev->mt76.dev, "Firmware already running...\n"); 16562306a36Sopenharmony_ci goto running; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) { 16962306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n"); 17062306a36Sopenharmony_ci ret = -EIO; 17162306a36Sopenharmony_ci goto out; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dl_len = le32_to_cpu(hdr->dl_len) + 4; 17562306a36Sopenharmony_ci ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); 17662306a36Sopenharmony_ci if (ret) { 17762306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Download request failed\n"); 17862306a36Sopenharmony_ci goto out; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER, 18262306a36Sopenharmony_ci fw->data, dl_len); 18362306a36Sopenharmony_ci if (ret) { 18462306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); 18562306a36Sopenharmony_ci goto out; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); 18962306a36Sopenharmony_ci if (ret) { 19062306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Failed to start firmware\n"); 19162306a36Sopenharmony_ci goto out; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { 19562306a36Sopenharmony_ci dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); 19662306a36Sopenharmony_ci ret = -EIO; 19762306a36Sopenharmony_ci goto out; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cirunning: 20162306a36Sopenharmony_ci mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci mt76_set(dev, MT_SCH_4, BIT(8)); 20462306a36Sopenharmony_ci mt76_clear(dev, MT_SCH_4, BIT(8)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci dev->mcu_running = true; 20762306a36Sopenharmony_ci snprintf(dev->mt76.hw->wiphy->fw_version, 20862306a36Sopenharmony_ci sizeof(dev->mt76.hw->wiphy->fw_version), 20962306a36Sopenharmony_ci "%.10s-%.15s", hdr->fw_ver, hdr->build_date); 21062306a36Sopenharmony_ci dev_info(dev->mt76.dev, "firmware init done\n"); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciout: 21362306a36Sopenharmony_ci release_firmware(fw); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return ret; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint mt7603_mcu_init(struct mt7603_dev *dev) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci static const struct mt76_mcu_ops mt7603_mcu_ops = { 22162306a36Sopenharmony_ci .headroom = sizeof(struct mt7603_mcu_txd), 22262306a36Sopenharmony_ci .mcu_skb_send_msg = mt7603_mcu_skb_send_msg, 22362306a36Sopenharmony_ci .mcu_parse_response = mt7603_mcu_parse_response, 22462306a36Sopenharmony_ci }; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci dev->mt76.mcu_ops = &mt7603_mcu_ops; 22762306a36Sopenharmony_ci return mt7603_load_firmware(dev); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_civoid mt7603_mcu_exit(struct mt7603_dev *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci mt7603_mcu_restart(&dev->mt76); 23362306a36Sopenharmony_ci skb_queue_purge(&dev->mt76.mcu.res_q); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciint mt7603_mcu_set_eeprom(struct mt7603_dev *dev) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci static const u16 req_fields[] = { 23962306a36Sopenharmony_ci#define WORD(_start) \ 24062306a36Sopenharmony_ci _start, \ 24162306a36Sopenharmony_ci _start + 1 24262306a36Sopenharmony_ci#define GROUP_2G(_start) \ 24362306a36Sopenharmony_ci WORD(_start), \ 24462306a36Sopenharmony_ci WORD(_start + 2), \ 24562306a36Sopenharmony_ci WORD(_start + 4) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci MT_EE_NIC_CONF_0 + 1, 24862306a36Sopenharmony_ci WORD(MT_EE_NIC_CONF_1), 24962306a36Sopenharmony_ci MT_EE_WIFI_RF_SETTING, 25062306a36Sopenharmony_ci MT_EE_TX_POWER_DELTA_BW40, 25162306a36Sopenharmony_ci MT_EE_TX_POWER_DELTA_BW80 + 1, 25262306a36Sopenharmony_ci MT_EE_TX_POWER_EXT_PA_5G, 25362306a36Sopenharmony_ci MT_EE_TEMP_SENSOR_CAL, 25462306a36Sopenharmony_ci GROUP_2G(MT_EE_TX_POWER_0_START_2G), 25562306a36Sopenharmony_ci GROUP_2G(MT_EE_TX_POWER_1_START_2G), 25662306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_CCK), 25762306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_6M), 25862306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_24M), 25962306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_OFDM_2G_54M), 26062306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_BPSK_QPSK), 26162306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_16_64_QAM), 26262306a36Sopenharmony_ci WORD(MT_EE_TX_POWER_HT_64_QAM), 26362306a36Sopenharmony_ci MT_EE_ELAN_RX_MODE_GAIN, 26462306a36Sopenharmony_ci MT_EE_ELAN_RX_MODE_NF, 26562306a36Sopenharmony_ci MT_EE_ELAN_RX_MODE_P1DB, 26662306a36Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_GAIN, 26762306a36Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_NF, 26862306a36Sopenharmony_ci MT_EE_ELAN_BYPASS_MODE_P1DB, 26962306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_6_7), 27062306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_4_5), 27162306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_2_3), 27262306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_NEG_0_1), 27362306a36Sopenharmony_ci WORD(MT_EE_REF_STEP_24G), 27462306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_1_2), 27562306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_3_4), 27662306a36Sopenharmony_ci WORD(MT_EE_STEP_NUM_PLUS_5_6), 27762306a36Sopenharmony_ci MT_EE_STEP_NUM_PLUS_7, 27862306a36Sopenharmony_ci MT_EE_XTAL_FREQ_OFFSET, 27962306a36Sopenharmony_ci MT_EE_XTAL_TRIM_2_COMP, 28062306a36Sopenharmony_ci MT_EE_XTAL_TRIM_3_COMP, 28162306a36Sopenharmony_ci MT_EE_XTAL_WF_RFCAL, 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* unknown fields below */ 28462306a36Sopenharmony_ci WORD(0x24), 28562306a36Sopenharmony_ci 0x34, 28662306a36Sopenharmony_ci 0x39, 28762306a36Sopenharmony_ci 0x3b, 28862306a36Sopenharmony_ci WORD(0x42), 28962306a36Sopenharmony_ci WORD(0x9e), 29062306a36Sopenharmony_ci 0xf2, 29162306a36Sopenharmony_ci WORD(0xf8), 29262306a36Sopenharmony_ci 0xfa, 29362306a36Sopenharmony_ci 0x12e, 29462306a36Sopenharmony_ci WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136), 29562306a36Sopenharmony_ci WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e), 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#undef GROUP_2G 29862306a36Sopenharmony_ci#undef WORD 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci }; 30162306a36Sopenharmony_ci struct req_data { 30262306a36Sopenharmony_ci __le16 addr; 30362306a36Sopenharmony_ci u8 val; 30462306a36Sopenharmony_ci u8 pad; 30562306a36Sopenharmony_ci } __packed; 30662306a36Sopenharmony_ci struct { 30762306a36Sopenharmony_ci u8 buffer_mode; 30862306a36Sopenharmony_ci u8 len; 30962306a36Sopenharmony_ci u8 pad[2]; 31062306a36Sopenharmony_ci } req_hdr = { 31162306a36Sopenharmony_ci .buffer_mode = 1, 31262306a36Sopenharmony_ci .len = ARRAY_SIZE(req_fields) - 1, 31362306a36Sopenharmony_ci }; 31462306a36Sopenharmony_ci const int size = 0xff * sizeof(struct req_data); 31562306a36Sopenharmony_ci u8 *req, *eep = (u8 *)dev->mt76.eeprom.data; 31662306a36Sopenharmony_ci int i, ret, len = sizeof(req_hdr) + size; 31762306a36Sopenharmony_ci struct req_data *data; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci req = kmalloc(len, GFP_KERNEL); 32262306a36Sopenharmony_ci if (!req) 32362306a36Sopenharmony_ci return -ENOMEM; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memcpy(req, &req_hdr, sizeof(req_hdr)); 32662306a36Sopenharmony_ci data = (struct req_data *)(req + sizeof(req_hdr)); 32762306a36Sopenharmony_ci memset(data, 0, size); 32862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req_fields); i++) { 32962306a36Sopenharmony_ci data[i].addr = cpu_to_le16(req_fields[i]); 33062306a36Sopenharmony_ci data[i].val = eep[req_fields[i]]; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, 33462306a36Sopenharmony_ci req, len, true); 33562306a36Sopenharmony_ci kfree(req); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return ret; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int mt7603_mcu_set_tx_power(struct mt7603_dev *dev) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct { 34362306a36Sopenharmony_ci u8 center_channel; 34462306a36Sopenharmony_ci u8 tssi; 34562306a36Sopenharmony_ci u8 temp_comp; 34662306a36Sopenharmony_ci u8 target_power[2]; 34762306a36Sopenharmony_ci u8 rate_power_delta[14]; 34862306a36Sopenharmony_ci u8 bw_power_delta; 34962306a36Sopenharmony_ci u8 ch_power_delta[6]; 35062306a36Sopenharmony_ci u8 temp_comp_power[17]; 35162306a36Sopenharmony_ci u8 reserved; 35262306a36Sopenharmony_ci } req = { 35362306a36Sopenharmony_ci .center_channel = dev->mphy.chandef.chan->hw_value, 35462306a36Sopenharmony_ci#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n] 35562306a36Sopenharmony_ci .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1), 35662306a36Sopenharmony_ci .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1), 35762306a36Sopenharmony_ci .target_power = { 35862306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2), 35962306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2) 36062306a36Sopenharmony_ci }, 36162306a36Sopenharmony_ci .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40), 36262306a36Sopenharmony_ci .ch_power_delta = { 36362306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3), 36462306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4), 36562306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5), 36662306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3), 36762306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4), 36862306a36Sopenharmony_ci EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5) 36962306a36Sopenharmony_ci }, 37062306a36Sopenharmony_ci#undef EEP_VAL 37162306a36Sopenharmony_ci }; 37262306a36Sopenharmony_ci u8 *eep = (u8 *)dev->mt76.eeprom.data; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK, 37562306a36Sopenharmony_ci sizeof(req.rate_power_delta)); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7, 37862306a36Sopenharmony_ci sizeof(req.temp_comp_power)); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL, 38162306a36Sopenharmony_ci &req, sizeof(req), true); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciint mt7603_mcu_set_channel(struct mt7603_dev *dev) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &dev->mphy.chandef; 38762306a36Sopenharmony_ci struct ieee80211_hw *hw = mt76_hw(dev); 38862306a36Sopenharmony_ci int n_chains = hweight8(dev->mphy.antenna_mask); 38962306a36Sopenharmony_ci struct { 39062306a36Sopenharmony_ci u8 control_chan; 39162306a36Sopenharmony_ci u8 center_chan; 39262306a36Sopenharmony_ci u8 bw; 39362306a36Sopenharmony_ci u8 tx_streams; 39462306a36Sopenharmony_ci u8 rx_streams; 39562306a36Sopenharmony_ci u8 _res0[7]; 39662306a36Sopenharmony_ci u8 txpower[21]; 39762306a36Sopenharmony_ci u8 _res1[3]; 39862306a36Sopenharmony_ci } req = { 39962306a36Sopenharmony_ci .control_chan = chandef->chan->hw_value, 40062306a36Sopenharmony_ci .center_chan = chandef->chan->hw_value, 40162306a36Sopenharmony_ci .bw = MT_BW_20, 40262306a36Sopenharmony_ci .tx_streams = n_chains, 40362306a36Sopenharmony_ci .rx_streams = n_chains, 40462306a36Sopenharmony_ci }; 40562306a36Sopenharmony_ci s8 tx_power = hw->conf.power_level * 2; 40662306a36Sopenharmony_ci int i, ret; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) { 40962306a36Sopenharmony_ci req.bw = MT_BW_40; 41062306a36Sopenharmony_ci if (chandef->center_freq1 > chandef->chan->center_freq) 41162306a36Sopenharmony_ci req.center_chan += 2; 41262306a36Sopenharmony_ci else 41362306a36Sopenharmony_ci req.center_chan -= 2; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power); 41762306a36Sopenharmony_ci if (dev->mphy.antenna_mask == 3) 41862306a36Sopenharmony_ci tx_power -= 6; 41962306a36Sopenharmony_ci tx_power = min(tx_power, dev->tx_power_limit); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci dev->mphy.txpower_cur = tx_power; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req.txpower); i++) 42462306a36Sopenharmony_ci req.txpower[i] = tx_power; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req, 42762306a36Sopenharmony_ci sizeof(req), true); 42862306a36Sopenharmony_ci if (ret) 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return mt7603_mcu_set_tx_power(dev); 43262306a36Sopenharmony_ci} 433