16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb
36c92544dSBjoern A. Zeeb #include <linux/firmware.h>
46c92544dSBjoern A. Zeeb #include "mt7603.h"
56c92544dSBjoern A. Zeeb #include "mcu.h"
66c92544dSBjoern A. Zeeb #include "eeprom.h"
76c92544dSBjoern A. Zeeb
86c92544dSBjoern A. Zeeb #define MCU_SKB_RESERVE 8
96c92544dSBjoern A. Zeeb
106c92544dSBjoern A. Zeeb struct mt7603_fw_trailer {
116c92544dSBjoern A. Zeeb char fw_ver[10];
126c92544dSBjoern A. Zeeb char build_date[15];
136c92544dSBjoern A. Zeeb __le32 dl_len;
146c92544dSBjoern A. Zeeb } __packed;
156c92544dSBjoern A. Zeeb
166c92544dSBjoern A. Zeeb static int
mt7603_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)176c92544dSBjoern A. Zeeb mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
186c92544dSBjoern A. Zeeb struct sk_buff *skb, int seq)
196c92544dSBjoern A. Zeeb {
206c92544dSBjoern A. Zeeb struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
216c92544dSBjoern A. Zeeb struct mt7603_mcu_rxd *rxd;
226c92544dSBjoern A. Zeeb
236c92544dSBjoern A. Zeeb if (!skb) {
246c92544dSBjoern A. Zeeb dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
256c92544dSBjoern A. Zeeb abs(cmd), seq);
266c92544dSBjoern A. Zeeb dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
276c92544dSBjoern A. Zeeb return -ETIMEDOUT;
286c92544dSBjoern A. Zeeb }
296c92544dSBjoern A. Zeeb
306c92544dSBjoern A. Zeeb rxd = (struct mt7603_mcu_rxd *)skb->data;
316c92544dSBjoern A. Zeeb if (seq != rxd->seq)
326c92544dSBjoern A. Zeeb return -EAGAIN;
336c92544dSBjoern A. Zeeb
346c92544dSBjoern A. Zeeb return 0;
356c92544dSBjoern A. Zeeb }
366c92544dSBjoern A. Zeeb
376c92544dSBjoern A. Zeeb static int
mt7603_mcu_skb_send_msg(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * wait_seq)386c92544dSBjoern A. Zeeb mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
396c92544dSBjoern A. Zeeb int cmd, int *wait_seq)
406c92544dSBjoern A. Zeeb {
416c92544dSBjoern A. Zeeb struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
426c92544dSBjoern A. Zeeb int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
436c92544dSBjoern A. Zeeb struct mt7603_mcu_txd *txd;
446c92544dSBjoern A. Zeeb u8 seq;
456c92544dSBjoern A. Zeeb
466c92544dSBjoern A. Zeeb mdev->mcu.timeout = 3 * HZ;
476c92544dSBjoern A. Zeeb
486c92544dSBjoern A. Zeeb seq = ++mdev->mcu.msg_seq & 0xf;
496c92544dSBjoern A. Zeeb if (!seq)
506c92544dSBjoern A. Zeeb seq = ++mdev->mcu.msg_seq & 0xf;
516c92544dSBjoern A. Zeeb
526c92544dSBjoern A. Zeeb txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
536c92544dSBjoern A. Zeeb
546c92544dSBjoern A. Zeeb txd->len = cpu_to_le16(skb->len);
556c92544dSBjoern A. Zeeb if (cmd == -MCU_CMD_FW_SCATTER)
566c92544dSBjoern A. Zeeb txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
576c92544dSBjoern A. Zeeb else
586c92544dSBjoern A. Zeeb txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
596c92544dSBjoern A. Zeeb txd->pkt_type = MCU_PKT_ID;
606c92544dSBjoern A. Zeeb txd->seq = seq;
616c92544dSBjoern A. Zeeb
626c92544dSBjoern A. Zeeb if (cmd < 0) {
636c92544dSBjoern A. Zeeb txd->cid = -cmd;
646c92544dSBjoern A. Zeeb txd->set_query = MCU_Q_NA;
656c92544dSBjoern A. Zeeb } else {
666c92544dSBjoern A. Zeeb txd->cid = MCU_CMD_EXT_CID;
676c92544dSBjoern A. Zeeb txd->ext_cid = cmd;
686c92544dSBjoern A. Zeeb txd->set_query = MCU_Q_SET;
696c92544dSBjoern A. Zeeb txd->ext_cid_ack = 1;
706c92544dSBjoern A. Zeeb }
716c92544dSBjoern A. Zeeb
726c92544dSBjoern A. Zeeb if (wait_seq)
736c92544dSBjoern A. Zeeb *wait_seq = seq;
746c92544dSBjoern A. Zeeb
756c92544dSBjoern A. Zeeb return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
766c92544dSBjoern A. Zeeb }
776c92544dSBjoern A. Zeeb
786c92544dSBjoern A. Zeeb static int
mt7603_mcu_init_download(struct mt7603_dev * dev,u32 addr,u32 len)796c92544dSBjoern A. Zeeb mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
806c92544dSBjoern A. Zeeb {
816c92544dSBjoern A. Zeeb struct {
826c92544dSBjoern A. Zeeb __le32 addr;
836c92544dSBjoern A. Zeeb __le32 len;
846c92544dSBjoern A. Zeeb __le32 mode;
856c92544dSBjoern A. Zeeb } req = {
866c92544dSBjoern A. Zeeb .addr = cpu_to_le32(addr),
876c92544dSBjoern A. Zeeb .len = cpu_to_le32(len),
886c92544dSBjoern A. Zeeb .mode = cpu_to_le32(BIT(31)),
896c92544dSBjoern A. Zeeb };
906c92544dSBjoern A. Zeeb
916c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
926c92544dSBjoern A. Zeeb &req, sizeof(req), true);
936c92544dSBjoern A. Zeeb }
946c92544dSBjoern A. Zeeb
956c92544dSBjoern A. Zeeb static int
mt7603_mcu_start_firmware(struct mt7603_dev * dev,u32 addr)966c92544dSBjoern A. Zeeb mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
976c92544dSBjoern A. Zeeb {
986c92544dSBjoern A. Zeeb struct {
996c92544dSBjoern A. Zeeb __le32 override;
1006c92544dSBjoern A. Zeeb __le32 addr;
1016c92544dSBjoern A. Zeeb } req = {
1026c92544dSBjoern A. Zeeb .override = cpu_to_le32(addr ? 1 : 0),
1036c92544dSBjoern A. Zeeb .addr = cpu_to_le32(addr),
1046c92544dSBjoern A. Zeeb };
1056c92544dSBjoern A. Zeeb
1066c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
1076c92544dSBjoern A. Zeeb sizeof(req), true);
1086c92544dSBjoern A. Zeeb }
1096c92544dSBjoern A. Zeeb
1106c92544dSBjoern A. Zeeb static int
mt7603_mcu_restart(struct mt76_dev * dev)1116c92544dSBjoern A. Zeeb mt7603_mcu_restart(struct mt76_dev *dev)
1126c92544dSBjoern A. Zeeb {
1136c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
1146c92544dSBjoern A. Zeeb }
1156c92544dSBjoern A. Zeeb
mt7603_load_firmware(struct mt7603_dev * dev)1166c92544dSBjoern A. Zeeb static int mt7603_load_firmware(struct mt7603_dev *dev)
1176c92544dSBjoern A. Zeeb {
1186c92544dSBjoern A. Zeeb const struct firmware *fw;
1196c92544dSBjoern A. Zeeb const struct mt7603_fw_trailer *hdr;
1206c92544dSBjoern A. Zeeb const char *firmware;
1216c92544dSBjoern A. Zeeb int dl_len;
1226c92544dSBjoern A. Zeeb u32 addr, val;
1236c92544dSBjoern A. Zeeb int ret;
1246c92544dSBjoern A. Zeeb
1256c92544dSBjoern A. Zeeb if (is_mt7628(dev)) {
1266c92544dSBjoern A. Zeeb if (mt76xx_rev(dev) == MT7628_REV_E1)
1276c92544dSBjoern A. Zeeb firmware = MT7628_FIRMWARE_E1;
1286c92544dSBjoern A. Zeeb else
1296c92544dSBjoern A. Zeeb firmware = MT7628_FIRMWARE_E2;
1306c92544dSBjoern A. Zeeb } else {
1316c92544dSBjoern A. Zeeb if (mt76xx_rev(dev) < MT7603_REV_E2)
1326c92544dSBjoern A. Zeeb firmware = MT7603_FIRMWARE_E1;
1336c92544dSBjoern A. Zeeb else
1346c92544dSBjoern A. Zeeb firmware = MT7603_FIRMWARE_E2;
1356c92544dSBjoern A. Zeeb }
1366c92544dSBjoern A. Zeeb
1376c92544dSBjoern A. Zeeb ret = request_firmware(&fw, firmware, dev->mt76.dev);
1386c92544dSBjoern A. Zeeb if (ret)
1396c92544dSBjoern A. Zeeb return ret;
1406c92544dSBjoern A. Zeeb
1416c92544dSBjoern A. Zeeb if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
1426c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Invalid firmware\n");
1436c92544dSBjoern A. Zeeb ret = -EINVAL;
1446c92544dSBjoern A. Zeeb goto out;
1456c92544dSBjoern A. Zeeb }
1466c92544dSBjoern A. Zeeb
1476c92544dSBjoern A. Zeeb hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
1486c92544dSBjoern A. Zeeb sizeof(*hdr));
1496c92544dSBjoern A. Zeeb
1506c92544dSBjoern A. Zeeb dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
1516c92544dSBjoern A. Zeeb dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
1526c92544dSBjoern A. Zeeb
1536c92544dSBjoern A. Zeeb addr = mt7603_reg_map(dev, 0x50012498);
1546c92544dSBjoern A. Zeeb mt76_wr(dev, addr, 0x5);
1556c92544dSBjoern A. Zeeb mt76_wr(dev, addr, 0x5);
1566c92544dSBjoern A. Zeeb udelay(1);
1576c92544dSBjoern A. Zeeb
1586c92544dSBjoern A. Zeeb /* switch to bypass mode */
1596c92544dSBjoern A. Zeeb mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
1606c92544dSBjoern A. Zeeb MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
1616c92544dSBjoern A. Zeeb
1626c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_TOP_MISC2);
1636c92544dSBjoern A. Zeeb if (val & BIT(1)) {
1646c92544dSBjoern A. Zeeb dev_info(dev->mt76.dev, "Firmware already running...\n");
1656c92544dSBjoern A. Zeeb goto running;
1666c92544dSBjoern A. Zeeb }
1676c92544dSBjoern A. Zeeb
1686c92544dSBjoern A. Zeeb if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
1696c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
1706c92544dSBjoern A. Zeeb ret = -EIO;
1716c92544dSBjoern A. Zeeb goto out;
1726c92544dSBjoern A. Zeeb }
1736c92544dSBjoern A. Zeeb
1746c92544dSBjoern A. Zeeb dl_len = le32_to_cpu(hdr->dl_len) + 4;
1756c92544dSBjoern A. Zeeb ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
1766c92544dSBjoern A. Zeeb if (ret) {
1776c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Download request failed\n");
1786c92544dSBjoern A. Zeeb goto out;
1796c92544dSBjoern A. Zeeb }
1806c92544dSBjoern A. Zeeb
1816c92544dSBjoern A. Zeeb ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
1826c92544dSBjoern A. Zeeb fw->data, dl_len);
1836c92544dSBjoern A. Zeeb if (ret) {
1846c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
1856c92544dSBjoern A. Zeeb goto out;
1866c92544dSBjoern A. Zeeb }
1876c92544dSBjoern A. Zeeb
1886c92544dSBjoern A. Zeeb ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
1896c92544dSBjoern A. Zeeb if (ret) {
1906c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Failed to start firmware\n");
1916c92544dSBjoern A. Zeeb goto out;
1926c92544dSBjoern A. Zeeb }
1936c92544dSBjoern A. Zeeb
1946c92544dSBjoern A. Zeeb if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
1956c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
1966c92544dSBjoern A. Zeeb ret = -EIO;
1976c92544dSBjoern A. Zeeb goto out;
1986c92544dSBjoern A. Zeeb }
1996c92544dSBjoern A. Zeeb
2006c92544dSBjoern A. Zeeb running:
2016c92544dSBjoern A. Zeeb mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
2026c92544dSBjoern A. Zeeb
2036c92544dSBjoern A. Zeeb mt76_set(dev, MT_SCH_4, BIT(8));
2046c92544dSBjoern A. Zeeb mt76_clear(dev, MT_SCH_4, BIT(8));
2056c92544dSBjoern A. Zeeb
2066c92544dSBjoern A. Zeeb dev->mcu_running = true;
2076c92544dSBjoern A. Zeeb snprintf(dev->mt76.hw->wiphy->fw_version,
2086c92544dSBjoern A. Zeeb sizeof(dev->mt76.hw->wiphy->fw_version),
2096c92544dSBjoern A. Zeeb "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
2106c92544dSBjoern A. Zeeb dev_info(dev->mt76.dev, "firmware init done\n");
2116c92544dSBjoern A. Zeeb
2126c92544dSBjoern A. Zeeb out:
2136c92544dSBjoern A. Zeeb release_firmware(fw);
2146c92544dSBjoern A. Zeeb
2156c92544dSBjoern A. Zeeb return ret;
2166c92544dSBjoern A. Zeeb }
2176c92544dSBjoern A. Zeeb
mt7603_mcu_init(struct mt7603_dev * dev)2186c92544dSBjoern A. Zeeb int mt7603_mcu_init(struct mt7603_dev *dev)
2196c92544dSBjoern A. Zeeb {
2206c92544dSBjoern A. Zeeb static const struct mt76_mcu_ops mt7603_mcu_ops = {
2216c92544dSBjoern A. Zeeb .headroom = sizeof(struct mt7603_mcu_txd),
2226c92544dSBjoern A. Zeeb .mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
2236c92544dSBjoern A. Zeeb .mcu_parse_response = mt7603_mcu_parse_response,
2246c92544dSBjoern A. Zeeb };
2256c92544dSBjoern A. Zeeb
2266c92544dSBjoern A. Zeeb dev->mt76.mcu_ops = &mt7603_mcu_ops;
2276c92544dSBjoern A. Zeeb return mt7603_load_firmware(dev);
2286c92544dSBjoern A. Zeeb }
2296c92544dSBjoern A. Zeeb
mt7603_mcu_exit(struct mt7603_dev * dev)2306c92544dSBjoern A. Zeeb void mt7603_mcu_exit(struct mt7603_dev *dev)
2316c92544dSBjoern A. Zeeb {
232*cbb3ec25SBjoern A. Zeeb mt7603_mcu_restart(&dev->mt76);
2336c92544dSBjoern A. Zeeb skb_queue_purge(&dev->mt76.mcu.res_q);
2346c92544dSBjoern A. Zeeb }
2356c92544dSBjoern A. Zeeb
mt7603_mcu_set_eeprom(struct mt7603_dev * dev)2366c92544dSBjoern A. Zeeb int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
2376c92544dSBjoern A. Zeeb {
2386c92544dSBjoern A. Zeeb static const u16 req_fields[] = {
2396c92544dSBjoern A. Zeeb #define WORD(_start) \
2406c92544dSBjoern A. Zeeb _start, \
2416c92544dSBjoern A. Zeeb _start + 1
2426c92544dSBjoern A. Zeeb #define GROUP_2G(_start) \
2436c92544dSBjoern A. Zeeb WORD(_start), \
2446c92544dSBjoern A. Zeeb WORD(_start + 2), \
2456c92544dSBjoern A. Zeeb WORD(_start + 4)
2466c92544dSBjoern A. Zeeb
2476c92544dSBjoern A. Zeeb MT_EE_NIC_CONF_0 + 1,
2486c92544dSBjoern A. Zeeb WORD(MT_EE_NIC_CONF_1),
2496c92544dSBjoern A. Zeeb MT_EE_WIFI_RF_SETTING,
2506c92544dSBjoern A. Zeeb MT_EE_TX_POWER_DELTA_BW40,
2516c92544dSBjoern A. Zeeb MT_EE_TX_POWER_DELTA_BW80 + 1,
2526c92544dSBjoern A. Zeeb MT_EE_TX_POWER_EXT_PA_5G,
2536c92544dSBjoern A. Zeeb MT_EE_TEMP_SENSOR_CAL,
2546c92544dSBjoern A. Zeeb GROUP_2G(MT_EE_TX_POWER_0_START_2G),
2556c92544dSBjoern A. Zeeb GROUP_2G(MT_EE_TX_POWER_1_START_2G),
2566c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_CCK),
2576c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_OFDM_2G_6M),
2586c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_OFDM_2G_24M),
2596c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_OFDM_2G_54M),
2606c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
2616c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_HT_16_64_QAM),
2626c92544dSBjoern A. Zeeb WORD(MT_EE_TX_POWER_HT_64_QAM),
2636c92544dSBjoern A. Zeeb MT_EE_ELAN_RX_MODE_GAIN,
2646c92544dSBjoern A. Zeeb MT_EE_ELAN_RX_MODE_NF,
2656c92544dSBjoern A. Zeeb MT_EE_ELAN_RX_MODE_P1DB,
2666c92544dSBjoern A. Zeeb MT_EE_ELAN_BYPASS_MODE_GAIN,
2676c92544dSBjoern A. Zeeb MT_EE_ELAN_BYPASS_MODE_NF,
2686c92544dSBjoern A. Zeeb MT_EE_ELAN_BYPASS_MODE_P1DB,
2696c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_NEG_6_7),
2706c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_NEG_4_5),
2716c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_NEG_2_3),
2726c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_NEG_0_1),
2736c92544dSBjoern A. Zeeb WORD(MT_EE_REF_STEP_24G),
2746c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_PLUS_1_2),
2756c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_PLUS_3_4),
2766c92544dSBjoern A. Zeeb WORD(MT_EE_STEP_NUM_PLUS_5_6),
2776c92544dSBjoern A. Zeeb MT_EE_STEP_NUM_PLUS_7,
2786c92544dSBjoern A. Zeeb MT_EE_XTAL_FREQ_OFFSET,
2796c92544dSBjoern A. Zeeb MT_EE_XTAL_TRIM_2_COMP,
2806c92544dSBjoern A. Zeeb MT_EE_XTAL_TRIM_3_COMP,
2816c92544dSBjoern A. Zeeb MT_EE_XTAL_WF_RFCAL,
2826c92544dSBjoern A. Zeeb
2836c92544dSBjoern A. Zeeb /* unknown fields below */
2846c92544dSBjoern A. Zeeb WORD(0x24),
2856c92544dSBjoern A. Zeeb 0x34,
2866c92544dSBjoern A. Zeeb 0x39,
2876c92544dSBjoern A. Zeeb 0x3b,
2886c92544dSBjoern A. Zeeb WORD(0x42),
2896c92544dSBjoern A. Zeeb WORD(0x9e),
2906c92544dSBjoern A. Zeeb 0xf2,
2916c92544dSBjoern A. Zeeb WORD(0xf8),
2926c92544dSBjoern A. Zeeb 0xfa,
2936c92544dSBjoern A. Zeeb 0x12e,
2946c92544dSBjoern A. Zeeb WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
2956c92544dSBjoern A. Zeeb WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
2966c92544dSBjoern A. Zeeb
2976c92544dSBjoern A. Zeeb #undef GROUP_2G
2986c92544dSBjoern A. Zeeb #undef WORD
2996c92544dSBjoern A. Zeeb
3006c92544dSBjoern A. Zeeb };
3016c92544dSBjoern A. Zeeb struct req_data {
3026c92544dSBjoern A. Zeeb __le16 addr;
3036c92544dSBjoern A. Zeeb u8 val;
3046c92544dSBjoern A. Zeeb u8 pad;
3056c92544dSBjoern A. Zeeb } __packed;
3066c92544dSBjoern A. Zeeb struct {
3076c92544dSBjoern A. Zeeb u8 buffer_mode;
3086c92544dSBjoern A. Zeeb u8 len;
3096c92544dSBjoern A. Zeeb u8 pad[2];
3106c92544dSBjoern A. Zeeb } req_hdr = {
3116c92544dSBjoern A. Zeeb .buffer_mode = 1,
3126c92544dSBjoern A. Zeeb .len = ARRAY_SIZE(req_fields) - 1,
3136c92544dSBjoern A. Zeeb };
3146c92544dSBjoern A. Zeeb const int size = 0xff * sizeof(struct req_data);
3156c92544dSBjoern A. Zeeb u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
3166c92544dSBjoern A. Zeeb int i, ret, len = sizeof(req_hdr) + size;
3176c92544dSBjoern A. Zeeb struct req_data *data;
3186c92544dSBjoern A. Zeeb
3196c92544dSBjoern A. Zeeb BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
3206c92544dSBjoern A. Zeeb
3216c92544dSBjoern A. Zeeb req = kmalloc(len, GFP_KERNEL);
3226c92544dSBjoern A. Zeeb if (!req)
3236c92544dSBjoern A. Zeeb return -ENOMEM;
3246c92544dSBjoern A. Zeeb
3256c92544dSBjoern A. Zeeb memcpy(req, &req_hdr, sizeof(req_hdr));
3266c92544dSBjoern A. Zeeb data = (struct req_data *)(req + sizeof(req_hdr));
3276c92544dSBjoern A. Zeeb memset(data, 0, size);
3286c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
3296c92544dSBjoern A. Zeeb data[i].addr = cpu_to_le16(req_fields[i]);
3306c92544dSBjoern A. Zeeb data[i].val = eep[req_fields[i]];
3316c92544dSBjoern A. Zeeb }
3326c92544dSBjoern A. Zeeb
3336c92544dSBjoern A. Zeeb ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
3346c92544dSBjoern A. Zeeb req, len, true);
3356c92544dSBjoern A. Zeeb kfree(req);
3366c92544dSBjoern A. Zeeb
3376c92544dSBjoern A. Zeeb return ret;
3386c92544dSBjoern A. Zeeb }
3396c92544dSBjoern A. Zeeb
mt7603_mcu_set_tx_power(struct mt7603_dev * dev)3406c92544dSBjoern A. Zeeb static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
3416c92544dSBjoern A. Zeeb {
3426c92544dSBjoern A. Zeeb struct {
3436c92544dSBjoern A. Zeeb u8 center_channel;
3446c92544dSBjoern A. Zeeb u8 tssi;
3456c92544dSBjoern A. Zeeb u8 temp_comp;
3466c92544dSBjoern A. Zeeb u8 target_power[2];
3476c92544dSBjoern A. Zeeb u8 rate_power_delta[14];
3486c92544dSBjoern A. Zeeb u8 bw_power_delta;
3496c92544dSBjoern A. Zeeb u8 ch_power_delta[6];
3506c92544dSBjoern A. Zeeb u8 temp_comp_power[17];
3516c92544dSBjoern A. Zeeb u8 reserved;
3526c92544dSBjoern A. Zeeb } req = {
3536c92544dSBjoern A. Zeeb .center_channel = dev->mphy.chandef.chan->hw_value,
3546c92544dSBjoern A. Zeeb #define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
3556c92544dSBjoern A. Zeeb .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
3566c92544dSBjoern A. Zeeb .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
3576c92544dSBjoern A. Zeeb .target_power = {
3586c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
3596c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
3606c92544dSBjoern A. Zeeb },
3616c92544dSBjoern A. Zeeb .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
3626c92544dSBjoern A. Zeeb .ch_power_delta = {
3636c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
3646c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
3656c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
3666c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
3676c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
3686c92544dSBjoern A. Zeeb EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
3696c92544dSBjoern A. Zeeb },
3706c92544dSBjoern A. Zeeb #undef EEP_VAL
3716c92544dSBjoern A. Zeeb };
3726c92544dSBjoern A. Zeeb u8 *eep = (u8 *)dev->mt76.eeprom.data;
3736c92544dSBjoern A. Zeeb
3746c92544dSBjoern A. Zeeb memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
3756c92544dSBjoern A. Zeeb sizeof(req.rate_power_delta));
3766c92544dSBjoern A. Zeeb
3776c92544dSBjoern A. Zeeb memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
3786c92544dSBjoern A. Zeeb sizeof(req.temp_comp_power));
3796c92544dSBjoern A. Zeeb
3806c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
3816c92544dSBjoern A. Zeeb &req, sizeof(req), true);
3826c92544dSBjoern A. Zeeb }
3836c92544dSBjoern A. Zeeb
mt7603_mcu_set_channel(struct mt7603_dev * dev)3846c92544dSBjoern A. Zeeb int mt7603_mcu_set_channel(struct mt7603_dev *dev)
3856c92544dSBjoern A. Zeeb {
3866c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
3876c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev);
3886c92544dSBjoern A. Zeeb int n_chains = hweight8(dev->mphy.antenna_mask);
3896c92544dSBjoern A. Zeeb struct {
3906c92544dSBjoern A. Zeeb u8 control_chan;
3916c92544dSBjoern A. Zeeb u8 center_chan;
3926c92544dSBjoern A. Zeeb u8 bw;
3936c92544dSBjoern A. Zeeb u8 tx_streams;
3946c92544dSBjoern A. Zeeb u8 rx_streams;
3956c92544dSBjoern A. Zeeb u8 _res0[7];
3966c92544dSBjoern A. Zeeb u8 txpower[21];
3976c92544dSBjoern A. Zeeb u8 _res1[3];
3986c92544dSBjoern A. Zeeb } req = {
3996c92544dSBjoern A. Zeeb .control_chan = chandef->chan->hw_value,
4006c92544dSBjoern A. Zeeb .center_chan = chandef->chan->hw_value,
4016c92544dSBjoern A. Zeeb .bw = MT_BW_20,
4026c92544dSBjoern A. Zeeb .tx_streams = n_chains,
4036c92544dSBjoern A. Zeeb .rx_streams = n_chains,
4046c92544dSBjoern A. Zeeb };
4056c92544dSBjoern A. Zeeb s8 tx_power = hw->conf.power_level * 2;
4066c92544dSBjoern A. Zeeb int i, ret;
4076c92544dSBjoern A. Zeeb
4086c92544dSBjoern A. Zeeb if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
4096c92544dSBjoern A. Zeeb req.bw = MT_BW_40;
4106c92544dSBjoern A. Zeeb if (chandef->center_freq1 > chandef->chan->center_freq)
4116c92544dSBjoern A. Zeeb req.center_chan += 2;
4126c92544dSBjoern A. Zeeb else
4136c92544dSBjoern A. Zeeb req.center_chan -= 2;
4146c92544dSBjoern A. Zeeb }
4156c92544dSBjoern A. Zeeb
4166c92544dSBjoern A. Zeeb tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power);
4176c92544dSBjoern A. Zeeb if (dev->mphy.antenna_mask == 3)
4186c92544dSBjoern A. Zeeb tx_power -= 6;
4196c92544dSBjoern A. Zeeb tx_power = min(tx_power, dev->tx_power_limit);
4206c92544dSBjoern A. Zeeb
4216c92544dSBjoern A. Zeeb dev->mphy.txpower_cur = tx_power;
4226c92544dSBjoern A. Zeeb
4236c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
4246c92544dSBjoern A. Zeeb req.txpower[i] = tx_power;
4256c92544dSBjoern A. Zeeb
4266c92544dSBjoern A. Zeeb ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
4276c92544dSBjoern A. Zeeb sizeof(req), true);
4286c92544dSBjoern A. Zeeb if (ret)
4296c92544dSBjoern A. Zeeb return ret;
4306c92544dSBjoern A. Zeeb
4316c92544dSBjoern A. Zeeb return mt7603_mcu_set_tx_power(dev);
4326c92544dSBjoern A. Zeeb }
433