Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76x2/pci_mcu.c
48525 views
// SPDX-License-Identifier: ISC1/*2* Copyright (C) 2016 Felix Fietkau <[email protected]>3*/45#include <linux/kernel.h>6#include <linux/firmware.h>7#include <linux/delay.h>89#include "mt76x2.h"10#include "mcu.h"11#include "eeprom.h"1213static int14mt76pci_load_rom_patch(struct mt76x02_dev *dev)15{16const struct firmware *fw = NULL;17struct mt76x02_patch_header *hdr;18bool rom_protect = !is_mt7612(dev);19int len, ret = 0;20__le32 *cur;21u32 patch_mask, patch_reg;2223if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) {24dev_err(dev->mt76.dev,25"Could not get hardware semaphore for ROM PATCH\n");26return -ETIMEDOUT;27}2829if (mt76xx_rev(dev) >= MT76XX_REV_E3) {30patch_mask = BIT(0);31patch_reg = MT_MCU_CLOCK_CTL;32} else {33patch_mask = BIT(1);34patch_reg = MT_MCU_COM_REG0;35}3637if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) {38dev_info(dev->mt76.dev, "ROM patch already applied\n");39goto out;40}4142ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev);43if (ret)44goto out;4546if (!fw || !fw->data || fw->size <= sizeof(*hdr)) {47ret = -EIO;48dev_err(dev->mt76.dev, "Failed to load firmware\n");49goto out;50}5152hdr = (struct mt76x02_patch_header *)fw->data;53dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);5455mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET);5657cur = (__le32 *)(fw->data + sizeof(*hdr));58len = fw->size - sizeof(*hdr);59mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len);6061mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);6263/* Trigger ROM */64mt76_wr(dev, MT_MCU_INT_LEVEL, 4);6566if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) {67dev_err(dev->mt76.dev, "Failed to load ROM patch\n");68ret = -ETIMEDOUT;69}7071out:72/* release semaphore */73if (rom_protect)74mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1);75release_firmware(fw);76return ret;77}7879static int80mt76pci_load_firmware(struct mt76x02_dev *dev)81{82const struct firmware *fw;83const struct mt76x02_fw_header *hdr;84int len, ret;85__le32 *cur;86u32 offset, val;8788ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev);89if (ret)90return ret;9192if (!fw || !fw->data || fw->size < sizeof(*hdr))93goto error;9495hdr = (const struct mt76x02_fw_header *)fw->data;9697len = sizeof(*hdr);98len += le32_to_cpu(hdr->ilm_len);99len += le32_to_cpu(hdr->dlm_len);100101if (fw->size != len)102goto error;103104val = le16_to_cpu(hdr->fw_ver);105dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",106(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);107108val = le16_to_cpu(hdr->build_ver);109dev_info(dev->mt76.dev, "Build: %x\n", val);110dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);111112cur = (__le32 *)(fw->data + sizeof(*hdr));113len = le32_to_cpu(hdr->ilm_len);114115mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET);116mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len);117118cur += len / sizeof(*cur);119len = le32_to_cpu(hdr->dlm_len);120121if (mt76xx_rev(dev) >= MT76XX_REV_E3)122offset = MT_MCU_DLM_ADDR_E3;123else124offset = MT_MCU_DLM_ADDR;125126mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);127mt76_wr_copy(dev, offset, cur, len);128129mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);130131val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2);132if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1)133mt76_set(dev, MT_MCU_COM_REG0, BIT(30));134135/* trigger firmware */136mt76_wr(dev, MT_MCU_INT_LEVEL, 2);137if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) {138dev_err(dev->mt76.dev, "Firmware failed to start\n");139release_firmware(fw);140return -ETIMEDOUT;141}142143mt76x02_set_ethtool_fwver(dev, hdr);144dev_info(dev->mt76.dev, "Firmware running!\n");145146release_firmware(fw);147148return ret;149150error:151dev_err(dev->mt76.dev, "Invalid firmware\n");152release_firmware(fw);153return -ENOENT;154}155156static int157mt76pci_mcu_restart(struct mt76_dev *mdev)158{159struct mt76x02_dev *dev;160int ret;161162dev = container_of(mdev, struct mt76x02_dev, mt76);163164mt76x02_mcu_cleanup(dev);165mt76x2_mac_reset(dev, true);166167ret = mt76pci_load_firmware(dev);168if (ret)169return ret;170171mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);172173return 0;174}175176int mt76x2_mcu_init(struct mt76x02_dev *dev)177{178static const struct mt76_mcu_ops mt76x2_mcu_ops = {179.mcu_restart = mt76pci_mcu_restart,180.mcu_send_msg = mt76x02_mcu_msg_send,181.mcu_parse_response = mt76x02_mcu_parse_response,182};183int ret;184185dev->mt76.mcu_ops = &mt76x2_mcu_ops;186187ret = mt76pci_load_rom_patch(dev);188if (ret)189return ret;190191ret = mt76pci_load_firmware(dev);192if (ret)193return ret;194195mt76x02_mcu_function_select(dev, Q_SELECT, 1);196return 0;197}198199200