Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/wireless/mediatek/mt76/mt7603/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 10 kB image not shown  

Quelle  mcu.c   Sprache: C

 
// SPDX-License-Identifier: ISC

#include <linux/firmware.h>
#include "mt7603.h"
#include "mcu.h"
#include "eeprom.h"

#define MCU_SKB_RESERVE 8

struct mt7603_fw_trailer {
 char fw_ver[10];
 char build_date[15];
 __le32 dl_len;
} __packed;

static int
mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
     struct sk_buff *skb, int seq)
{
 struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
 struct mt7603_mcu_rxd *rxd;

 if (!skb) {
  dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
   abs(cmd), seq);
  dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
  return -ETIMEDOUT;
 }

 rxd = (struct mt7603_mcu_rxd *)skb->data;
 if (seq != rxd->seq)
  return -EAGAIN;

 return 0;
}

static int
mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
   int cmd, int *wait_seq)
{
 struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
 int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
 struct mt7603_mcu_txd *txd;
 u8 seq;

 mdev->mcu.timeout = 3 * HZ;

 seq = ++mdev->mcu.msg_seq & 0xf;
 if (!seq)
  seq = ++mdev->mcu.msg_seq & 0xf;

 txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);

 txd->len = cpu_to_le16(skb->len);
 if (cmd == -MCU_CMD_FW_SCATTER)
  txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
 else
  txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
 txd->pkt_type = MCU_PKT_ID;
 txd->seq = seq;

 if (cmd < 0) {
  txd->cid = -cmd;
  txd->set_query = MCU_Q_NA;
 } else {
  txd->cid = MCU_CMD_EXT_CID;
  txd->ext_cid = cmd;
  txd->set_query = MCU_Q_SET;
  txd->ext_cid_ack = 1;
 }

 if (wait_seq)
  *wait_seq = seq;

 return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
}

static int
mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
{
 struct {
  __le32 addr;
  __le32 len;
  __le32 mode;
 } req = {
  .addr = cpu_to_le32(addr),
  .len = cpu_to_le32(len),
  .mode = cpu_to_le32(BIT(31)),
 };

 return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
     &req, sizeof(req), true);
}

static int
mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
{
 struct {
  __le32 override;
  __le32 addr;
 } req = {
  .override = cpu_to_le32(addr ? 1 : 0),
  .addr = cpu_to_le32(addr),
 };

 return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
     sizeof(req), true);
}

static int
mt7603_mcu_restart(struct mt76_dev *dev)
{
 return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
}

static int mt7603_load_firmware(struct mt7603_dev *dev)
{
 const struct firmware *fw;
 const struct mt7603_fw_trailer *hdr;
 const char *firmware;
 int dl_len;
 u32 addr, val;
 int ret;

 if (is_mt7628(dev)) {
  if (mt76xx_rev(dev) == MT7628_REV_E1)
   firmware = MT7628_FIRMWARE_E1;
  else
   firmware = MT7628_FIRMWARE_E2;
 } else {
  if (mt76xx_rev(dev) < MT7603_REV_E2)
   firmware = MT7603_FIRMWARE_E1;
  else
   firmware = MT7603_FIRMWARE_E2;
 }

 ret = request_firmware(&fw, firmware, dev->mt76.dev);
 if (ret)
  return ret;

 if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
  dev_err(dev->mt76.dev, "Invalid firmware\n");
  ret = -EINVAL;
  goto out;
 }

 hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
       sizeof(*hdr));

 dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
 dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);

 addr = mt7603_reg_map(dev, 0x50012498);
 mt76_wr(dev, addr, 0x5);
 mt76_wr(dev, addr, 0x5);
 udelay(1);

 /* switch to bypass mode */
 mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
   MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));

 val = mt76_rr(dev, MT_TOP_MISC2);
 if (val & BIT(1)) {
  dev_info(dev->mt76.dev, "Firmware already running...\n");
  goto running;
 }

 if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
  dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
  ret = -EIO;
  goto out;
 }

 dl_len = le32_to_cpu(hdr->dl_len) + 4;
 ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
 if (ret) {
  dev_err(dev->mt76.dev, "Download request failed\n");
  goto out;
 }

 ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
         fw->data, dl_len);
 if (ret) {
  dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
  goto out;
 }

 ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
 if (ret) {
  dev_err(dev->mt76.dev, "Failed to start firmware\n");
  goto out;
 }

 if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
  dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
  ret = -EIO;
  goto out;
 }

running:
 mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);

 mt76_set(dev, MT_SCH_4, BIT(8));
 mt76_clear(dev, MT_SCH_4, BIT(8));

 dev->mcu_running = true;
 snprintf(dev->mt76.hw->wiphy->fw_version,
   sizeof(dev->mt76.hw->wiphy->fw_version),
   "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
 dev_info(dev->mt76.dev, "firmware init done\n");

out:
 release_firmware(fw);

 return ret;
}

int mt7603_mcu_init(struct mt7603_dev *dev)
{
 static const struct mt76_mcu_ops mt7603_mcu_ops = {
  .headroom = sizeof(struct mt7603_mcu_txd),
  .mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
  .mcu_parse_response = mt7603_mcu_parse_response,
 };

 dev->mt76.mcu_ops = &mt7603_mcu_ops;
 return mt7603_load_firmware(dev);
}

void mt7603_mcu_exit(struct mt7603_dev *dev)
{
 mt7603_mcu_restart(&dev->mt76);
 skb_queue_purge(&dev->mt76.mcu.res_q);
}

int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
{
 static const u16 req_fields[] = {
#define WORD(_start)   \
  _start,   \
  _start + 1
#define GROUP_2G(_start)  \
  WORD(_start),  \
  WORD(_start + 2), \
  WORD(_start + 4)

  MT_EE_NIC_CONF_0 + 1,
  WORD(MT_EE_NIC_CONF_1),
  MT_EE_WIFI_RF_SETTING,
  MT_EE_TX_POWER_DELTA_BW40,
  MT_EE_TX_POWER_DELTA_BW80 + 1,
  MT_EE_TX_POWER_EXT_PA_5G,
  MT_EE_TEMP_SENSOR_CAL,
  GROUP_2G(MT_EE_TX_POWER_0_START_2G),
  GROUP_2G(MT_EE_TX_POWER_1_START_2G),
  WORD(MT_EE_TX_POWER_CCK),
  WORD(MT_EE_TX_POWER_OFDM_2G_6M),
  WORD(MT_EE_TX_POWER_OFDM_2G_24M),
  WORD(MT_EE_TX_POWER_OFDM_2G_54M),
  WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
  WORD(MT_EE_TX_POWER_HT_16_64_QAM),
  WORD(MT_EE_TX_POWER_HT_64_QAM),
  MT_EE_ELAN_RX_MODE_GAIN,
  MT_EE_ELAN_RX_MODE_NF,
  MT_EE_ELAN_RX_MODE_P1DB,
  MT_EE_ELAN_BYPASS_MODE_GAIN,
  MT_EE_ELAN_BYPASS_MODE_NF,
  MT_EE_ELAN_BYPASS_MODE_P1DB,
  WORD(MT_EE_STEP_NUM_NEG_6_7),
  WORD(MT_EE_STEP_NUM_NEG_4_5),
  WORD(MT_EE_STEP_NUM_NEG_2_3),
  WORD(MT_EE_STEP_NUM_NEG_0_1),
  WORD(MT_EE_REF_STEP_24G),
  WORD(MT_EE_STEP_NUM_PLUS_1_2),
  WORD(MT_EE_STEP_NUM_PLUS_3_4),
  WORD(MT_EE_STEP_NUM_PLUS_5_6),
  MT_EE_STEP_NUM_PLUS_7,
  MT_EE_XTAL_FREQ_OFFSET,
  MT_EE_XTAL_TRIM_2_COMP,
  MT_EE_XTAL_TRIM_3_COMP,
  MT_EE_XTAL_WF_RFCAL,

  /* unknown fields below */
  WORD(0x24),
  0x34,
  0x39,
  0x3b,
  WORD(0x42),
  WORD(0x9e),
  0xf2,
  WORD(0xf8),
  0xfa,
  0x12e,
  WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
  WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),

#undef GROUP_2G
#undef WORD

 };
 struct req_data {
  __le16 addr;
  u8 val;
  u8 pad;
 } __packed;
 struct {
  u8 buffer_mode;
  u8 len;
  u8 pad[2];
 } req_hdr = {
  .buffer_mode = 1,
  .len = ARRAY_SIZE(req_fields) - 1,
 };
 const int size = 0xff * sizeof(struct req_data);
 u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
 int i, ret, len = sizeof(req_hdr) + size;
 struct req_data *data;

 BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);

 req = kmalloc(len, GFP_KERNEL);
 if (!req)
  return -ENOMEM;

 memcpy(req, &req_hdr, sizeof(req_hdr));
 data = (struct req_data *)(req + sizeof(req_hdr));
 memset(data, 0, size);
 for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
  data[i].addr = cpu_to_le16(req_fields[i]);
  data[i].val = eep[req_fields[i]];
 }

 ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
    req, len, true);
 kfree(req);

 return ret;
}

static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
{
 struct {
  u8 center_channel;
  u8 tssi;
  u8 temp_comp;
  u8 target_power[2];
  u8 rate_power_delta[14];
  u8 bw_power_delta;
  u8 ch_power_delta[6];
  u8 temp_comp_power[17];
  u8 reserved;
 } req = {
  .center_channel = dev->mphy.chandef.chan->hw_value,
#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
  .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
  .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
  .target_power = {
   EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
   EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
  },
  .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
  .ch_power_delta = {
   EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
   EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
   EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
   EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
   EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
   EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
  },
#undef EEP_VAL
 };
 u8 *eep = (u8 *)dev->mt76.eeprom.data;

 memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
        sizeof(req.rate_power_delta));

 memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
        sizeof(req.temp_comp_power));

 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
     &req, sizeof(req), true);
}

int mt7603_mcu_set_channel(struct mt7603_dev *dev)
{
 struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
 struct ieee80211_hw *hw = mt76_hw(dev);
 int n_chains = hweight8(dev->mphy.antenna_mask);
 struct {
  u8 control_chan;
  u8 center_chan;
  u8 bw;
  u8 tx_streams;
  u8 rx_streams;
  u8 _res0[7];
  u8 txpower[21];
  u8 _res1[3];
 } req = {
  .control_chan = chandef->chan->hw_value,
  .center_chan = chandef->chan->hw_value,
  .bw = MT_BW_20,
  .tx_streams = n_chains,
  .rx_streams = n_chains,
 };
 s8 tx_power = hw->conf.power_level * 2;
 int i, ret;

 if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_40) {
  req.bw = MT_BW_40;
  if (chandef->center_freq1 > chandef->chan->center_freq)
   req.center_chan += 2;
  else
   req.center_chan -= 2;
 }

 tx_power = mt76_get_sar_power(&dev->mphy, chandef->chan, tx_power);
 if (dev->mphy.antenna_mask == 3)
  tx_power -= 6;
 tx_power = min(tx_power, dev->tx_power_limit);

 dev->mphy.txpower_cur = tx_power;

 for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
  req.txpower[i] = tx_power;

 ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
    sizeof(req), true);
 if (ret)
  return ret;

 return mt7603_mcu_set_tx_power(dev);
}

Messung V0.5
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.