Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7603/mcu.c
48524 views
// SPDX-License-Identifier: ISC12#include <linux/firmware.h>3#include "mt7603.h"4#include "mcu.h"5#include "eeprom.h"67#define MCU_SKB_RESERVE 889struct mt7603_fw_trailer {10char fw_ver[10];11char build_date[15];12__le32 dl_len;13} __packed;1415static int16mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,17struct sk_buff *skb, int seq)18{19struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);20struct mt7603_mcu_rxd *rxd;2122if (!skb) {23dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",24abs(cmd), seq);25dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;26return -ETIMEDOUT;27}2829rxd = (struct mt7603_mcu_rxd *)skb->data;30if (seq != rxd->seq)31return -EAGAIN;3233return 0;34}3536static int37mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,38int cmd, int *wait_seq)39{40struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);41int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;42struct mt7603_mcu_txd *txd;43u8 seq;4445mdev->mcu.timeout = 3 * HZ;4647seq = ++mdev->mcu.msg_seq & 0xf;48if (!seq)49seq = ++mdev->mcu.msg_seq & 0xf;5051txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);5253txd->len = cpu_to_le16(skb->len);54if (cmd == -MCU_CMD_FW_SCATTER)55txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);56else57txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);58txd->pkt_type = MCU_PKT_ID;59txd->seq = seq;6061if (cmd < 0) {62txd->cid = -cmd;63txd->set_query = MCU_Q_NA;64} else {65txd->cid = MCU_CMD_EXT_CID;66txd->ext_cid = cmd;67txd->set_query = MCU_Q_SET;68txd->ext_cid_ack = 1;69}7071if (wait_seq)72*wait_seq = seq;7374return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);75}7677static int78mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)79{80struct {81__le32 addr;82__le32 len;83__le32 mode;84} req = {85.addr = cpu_to_le32(addr),86.len = cpu_to_le32(len),87.mode = cpu_to_le32(BIT(31)),88};8990return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,91&req, sizeof(req), true);92}9394static int95mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)96{97struct {98__le32 override;99__le32 addr;100} req = {101.override = cpu_to_le32(addr ? 1 : 0),102.addr = cpu_to_le32(addr),103};104105return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,106sizeof(req), true);107}108109static int110mt7603_mcu_restart(struct mt76_dev *dev)111{112return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);113}114115static int mt7603_load_firmware(struct mt7603_dev *dev)116{117const struct firmware *fw;118const struct mt7603_fw_trailer *hdr;119const char *firmware;120int dl_len;121u32 addr, val;122int ret;123124if (is_mt7628(dev)) {125if (mt76xx_rev(dev) == MT7628_REV_E1)126firmware = MT7628_FIRMWARE_E1;127else128firmware = MT7628_FIRMWARE_E2;129} else {130if (mt76xx_rev(dev) < MT7603_REV_E2)131firmware = MT7603_FIRMWARE_E1;132else133firmware = MT7603_FIRMWARE_E2;134}135136ret = request_firmware(&fw, firmware, dev->mt76.dev);137if (ret)138return ret;139140if (!fw || !fw->data || fw->size < sizeof(*hdr)) {141dev_err(dev->mt76.dev, "Invalid firmware\n");142ret = -EINVAL;143goto out;144}145146hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -147sizeof(*hdr));148149dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);150dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);151152addr = mt7603_reg_map(dev, 0x50012498);153mt76_wr(dev, addr, 0x5);154mt76_wr(dev, addr, 0x5);155udelay(1);156157/* switch to bypass mode */158mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,159MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));160161val = mt76_rr(dev, MT_TOP_MISC2);162if (val & BIT(1)) {163dev_info(dev->mt76.dev, "Firmware already running...\n");164goto running;165}166167if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {168dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");169ret = -EIO;170goto out;171}172173dl_len = le32_to_cpu(hdr->dl_len) + 4;174ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);175if (ret) {176dev_err(dev->mt76.dev, "Download request failed\n");177goto out;178}179180ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,181fw->data, dl_len);182if (ret) {183dev_err(dev->mt76.dev, "Failed to send firmware to device\n");184goto out;185}186187ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);188if (ret) {189dev_err(dev->mt76.dev, "Failed to start firmware\n");190goto out;191}192193if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {194dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");195ret = -EIO;196goto out;197}198199running:200mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);201202mt76_set(dev, MT_SCH_4, BIT(8));203mt76_clear(dev, MT_SCH_4, BIT(8));204205dev->mcu_running = true;206snprintf(dev->mt76.hw->wiphy->fw_version,207sizeof(dev->mt76.hw->wiphy->fw_version),208"%.10s-%.15s", hdr->fw_ver, hdr->build_date);209dev_info(dev->mt76.dev, "firmware init done\n");210211out:212release_firmware(fw);213214return ret;215}216217int mt7603_mcu_init(struct mt7603_dev *dev)218{219static const struct mt76_mcu_ops mt7603_mcu_ops = {220.headroom = sizeof(struct mt7603_mcu_txd),221.mcu_skb_send_msg = mt7603_mcu_skb_send_msg,222.mcu_parse_response = mt7603_mcu_parse_response,223};224225dev->mt76.mcu_ops = &mt7603_mcu_ops;226return mt7603_load_firmware(dev);227}228229void mt7603_mcu_exit(struct mt7603_dev *dev)230{231mt7603_mcu_restart(&dev->mt76);232skb_queue_purge(&dev->mt76.mcu.res_q);233}234235int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)236{237static const u16 req_fields[] = {238#define WORD(_start) \239_start, \240_start + 1241#define GROUP_2G(_start) \242WORD(_start), \243WORD(_start + 2), \244WORD(_start + 4)245246MT_EE_NIC_CONF_0 + 1,247WORD(MT_EE_NIC_CONF_1),248MT_EE_WIFI_RF_SETTING,249MT_EE_TX_POWER_DELTA_BW40,250MT_EE_TX_POWER_DELTA_BW80 + 1,251MT_EE_TX_POWER_EXT_PA_5G,252MT_EE_TEMP_SENSOR_CAL,253GROUP_2G(MT_EE_TX_POWER_0_START_2G),254GROUP_2G(MT_EE_TX_POWER_1_START_2G),255WORD(MT_EE_TX_POWER_CCK),256WORD(MT_EE_TX_POWER_OFDM_2G_6M),257WORD(MT_EE_TX_POWER_OFDM_2G_24M),258WORD(MT_EE_TX_POWER_OFDM_2G_54M),259WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),260WORD(MT_EE_TX_POWER_HT_16_64_QAM),261WORD(MT_EE_TX_POWER_HT_64_QAM),262MT_EE_ELAN_RX_MODE_GAIN,263MT_EE_ELAN_RX_MODE_NF,264MT_EE_ELAN_RX_MODE_P1DB,265MT_EE_ELAN_BYPASS_MODE_GAIN,266MT_EE_ELAN_BYPASS_MODE_NF,267MT_EE_ELAN_BYPASS_MODE_P1DB,268WORD(MT_EE_STEP_NUM_NEG_6_7),269WORD(MT_EE_STEP_NUM_NEG_4_5),270WORD(MT_EE_STEP_NUM_NEG_2_3),271WORD(MT_EE_STEP_NUM_NEG_0_1),272WORD(MT_EE_REF_STEP_24G),273WORD(MT_EE_STEP_NUM_PLUS_1_2),274WORD(MT_EE_STEP_NUM_PLUS_3_4),275WORD(MT_EE_STEP_NUM_PLUS_5_6),276MT_EE_STEP_NUM_PLUS_7,277MT_EE_XTAL_FREQ_OFFSET,278MT_EE_XTAL_TRIM_2_COMP,279MT_EE_XTAL_TRIM_3_COMP,280MT_EE_XTAL_WF_RFCAL,281282/* unknown fields below */283WORD(0x24),2840x34,2850x39,2860x3b,287WORD(0x42),288WORD(0x9e),2890xf2,290WORD(0xf8),2910xfa,2920x12e,293WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),294WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),295296#undef GROUP_2G297#undef WORD298299};300struct req_data {301__le16 addr;302u8 val;303u8 pad;304} __packed;305struct {306u8 buffer_mode;307u8 len;308u8 pad[2];309} req_hdr = {310.buffer_mode = 1,311.len = ARRAY_SIZE(req_fields) - 1,312};313const int size = 0xff * sizeof(struct req_data);314u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;315int i, ret, len = sizeof(req_hdr) + size;316struct req_data *data;317318BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);319320req = kmalloc(len, GFP_KERNEL);321if (!req)322return -ENOMEM;323324memcpy(req, &req_hdr, sizeof(req_hdr));325data = (struct req_data *)(req + sizeof(req_hdr));326memset(data, 0, size);327for (i = 0; i < ARRAY_SIZE(req_fields); i++) {328data[i].addr = cpu_to_le16(req_fields[i]);329data[i].val = eep[req_fields[i]];330}331332ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,333req, len, true);334kfree(req);335336return ret;337}338339static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)340{341struct {342u8 center_channel;343u8 tssi;344u8 temp_comp;345u8 target_power[2];346u8 rate_power_delta[14];347u8 bw_power_delta;348u8 ch_power_delta[6];349u8 temp_comp_power[17];350u8 reserved;351} req = {352.center_channel = dev->mphy.chandef.chan->hw_value,353#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]354.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),355.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),356.target_power = {357EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),358EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)359},360.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),361.ch_power_delta = {362EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),363EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),364EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),365EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),366EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),367EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)368},369#undef EEP_VAL370};371u8 *eep = (u8 *)dev->mt76.eeprom.data;372373memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,374sizeof(req.rate_power_delta));375376memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,377sizeof(req.temp_comp_power));378379return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,380&req, sizeof(req), true);381}382383int mt7603_mcu_set_channel(struct mt7603_dev *dev)384{385struct cfg80211_chan_def *chandef = &dev->mphy.chandef;386struct ieee80211_hw *hw = mt76_hw(dev);387int n_chains = hweight8(dev->mphy.antenna_mask);388struct {389u8 control_chan;390u8 center_chan;391u8 bw;392u8 tx_streams;393u8 rx_streams;394u8 _res0[7];395u8 txpower[21];396u8 _res1[3];397} req = {398.control_chan = chandef->chan->hw_value,399.center_chan = chandef->chan->hw_value,400.bw = MT_BW_20,401.tx_streams = n_chains,402.rx_streams = n_chains,403};404s8 tx_power = hw->conf.power_level * 2;405int i, ret;406407if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {408req.bw = MT_BW_40;409if (chandef->center_freq1 > chandef->chan->center_freq)410req.center_chan += 2;411else412req.center_chan -= 2;413}414415tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power);416if (dev->mphy.antenna_mask == 3)417tx_power -= 6;418tx_power = min(tx_power, dev->tx_power_limit);419420dev->mphy.txpower_cur = tx_power;421422for (i = 0; i < ARRAY_SIZE(req.txpower); i++)423req.txpower[i] = tx_power;424425ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,426sizeof(req), true);427if (ret)428return ret;429430return mt7603_mcu_set_tx_power(dev);431}432433434