134 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>4 */5#include <linux/kernel.h>6#include <linux/firmware.h>7 8#include "mt76x0.h"9#include "mcu.h"10 11#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE)12 13static int mt76x0e_load_firmware(struct mt76x02_dev *dev)14{15 bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610;16 u32 val, ilm_len, dlm_len, offset = 0;17 const struct mt76x02_fw_header *hdr;18 const struct firmware *fw;19 const char *firmware;20 const u8 *fw_payload;21 int len, err;22 23 if (is_combo_chip)24 firmware = MT7650E_FIRMWARE;25 else26 firmware = MT7610E_FIRMWARE;27 28 err = request_firmware(&fw, firmware, dev->mt76.dev);29 if (err)30 return err;31 32 if (!fw || !fw->data || fw->size < sizeof(*hdr)) {33 err = -EIO;34 goto out;35 }36 37 hdr = (const struct mt76x02_fw_header *)fw->data;38 39 len = sizeof(*hdr);40 len += le32_to_cpu(hdr->ilm_len);41 len += le32_to_cpu(hdr->dlm_len);42 43 if (fw->size != len) {44 err = -EIO;45 goto out;46 }47 48 fw_payload = fw->data + sizeof(*hdr);49 50 val = le16_to_cpu(hdr->fw_ver);51 dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",52 (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);53 54 val = le16_to_cpu(hdr->fw_ver);55 dev_dbg(dev->mt76.dev,56 "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",57 (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,58 le16_to_cpu(hdr->build_ver), hdr->build_time);59 60 if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) {61 dev_err(dev->mt76.dev,62 "Could not get hardware semaphore for loading fw\n");63 err = -ETIMEDOUT;64 goto out;65 }66 67 /* upload ILM. */68 mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);69 ilm_len = le32_to_cpu(hdr->ilm_len);70 if (is_combo_chip) {71 ilm_len -= MT_MCU_IVB_SIZE;72 offset = MT_MCU_IVB_SIZE;73 }74 dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len);75 mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset,76 ilm_len);77 78 /* upload IVB. */79 if (is_combo_chip) {80 dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n",81 MT_MCU_IVB_SIZE);82 mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE);83 }84 85 /* upload DLM. */86 mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);87 dlm_len = le32_to_cpu(hdr->dlm_len);88 dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);89 mt76_wr_copy(dev, MT_MCU_ILM_ADDR,90 fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len);91 92 /* trigger firmware */93 mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);94 if (is_combo_chip)95 mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3);96 else97 mt76_wr(dev, MT_MCU_RESET_CTL, 0x300);98 99 if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {100 dev_err(dev->mt76.dev, "Firmware failed to start\n");101 err = -ETIMEDOUT;102 goto out;103 }104 105 mt76x02_set_ethtool_fwver(dev, hdr);106 dev_dbg(dev->mt76.dev, "Firmware running!\n");107 108out:109 if (is_combo_chip)110 mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1);111 release_firmware(fw);112 113 return err;114}115 116int mt76x0e_mcu_init(struct mt76x02_dev *dev)117{118 static const struct mt76_mcu_ops mt76x0e_mcu_ops = {119 .mcu_send_msg = mt76x02_mcu_msg_send,120 .mcu_parse_response = mt76x02_mcu_parse_response,121 };122 int err;123 124 dev->mt76.mcu_ops = &mt76x0e_mcu_ops;125 126 err = mt76x0e_load_firmware(dev);127 if (err < 0)128 return err;129 130 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);131 132 return 0;133}134