Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76x2/usb_mcu.c
48525 views
// SPDX-License-Identifier: ISC1/*2* Copyright (C) 2018 Lorenzo Bianconi <[email protected]>3*/45#include <linux/firmware.h>67#include "mt76x2u.h"8#include "eeprom.h"9#include "../mt76x02_usb.h"1011#define MT_CMD_HDR_LEN 41213#define MCU_FW_URB_MAX_PAYLOAD 0x390014#define MCU_ROM_PATCH_MAX_PAYLOAD 20481516#define MT76U_MCU_ILM_OFFSET 0x8000017#define MT76U_MCU_DLM_OFFSET 0x11000018#define MT76U_MCU_ROM_PATCH_OFFSET 0x900001920static void mt76x2u_mcu_load_ivb(struct mt76x02_dev *dev)21{22mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,23USB_DIR_OUT | USB_TYPE_VENDOR,240x12, 0, NULL, 0);25}2627static void mt76x2u_mcu_enable_patch(struct mt76x02_dev *dev)28{29struct mt76_usb *usb = &dev->mt76.usb;30static const u8 data[] = {310x6f, 0xfc, 0x08, 0x01,320x20, 0x04, 0x00, 0x00,330x00, 0x09, 0x00,34};3536memcpy(usb->data, data, sizeof(data));37mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,38USB_DIR_OUT | USB_TYPE_CLASS,390x12, 0, usb->data, sizeof(data));40}4142static void mt76x2u_mcu_reset_wmt(struct mt76x02_dev *dev)43{44struct mt76_usb *usb = &dev->mt76.usb;45u8 data[] = {460x6f, 0xfc, 0x05, 0x01,470x07, 0x01, 0x00, 0x0448};4950memcpy(usb->data, data, sizeof(data));51mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,52USB_DIR_OUT | USB_TYPE_CLASS,530x12, 0, usb->data, sizeof(data));54}5556static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev)57{58bool rom_protect = !is_mt7612(dev);59struct mt76x02_patch_header *hdr;60u32 val, patch_mask, patch_reg;61const struct firmware *fw;62int err;6364if (rom_protect &&65!mt76_poll_msec(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) {66dev_err(dev->mt76.dev,67"could not get hardware semaphore for ROM PATCH\n");68return -ETIMEDOUT;69}7071if (mt76xx_rev(dev) >= MT76XX_REV_E3) {72patch_mask = BIT(0);73patch_reg = MT_MCU_CLOCK_CTL;74} else {75patch_mask = BIT(1);76patch_reg = MT_MCU_COM_REG0;77}7879if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) {80dev_info(dev->mt76.dev, "ROM patch already applied\n");81return 0;82}8384err = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev);85if (err < 0)86return err;8788if (!fw || !fw->data || fw->size <= sizeof(*hdr)) {89dev_err(dev->mt76.dev, "failed to load firmware\n");90err = -EIO;91goto out;92}9394hdr = (struct mt76x02_patch_header *)fw->data;95dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);9697/* enable USB_DMA_CFG */98val = MT_USB_DMA_CFG_RX_BULK_EN |99MT_USB_DMA_CFG_TX_BULK_EN |100FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20);101mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);102103/* vendor reset */104mt76x02u_mcu_fw_reset(dev);105usleep_range(5000, 10000);106107/* enable FCE to send in-band cmd */108mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);109/* FCE tx_fs_base_ptr */110mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);111/* FCE tx_fs_max_cnt */112mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 0x1);113/* FCE pdma enable */114mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);115/* FCE skip_fs_en */116mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);117118err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),119fw->size - sizeof(*hdr),120MCU_ROM_PATCH_MAX_PAYLOAD,121MT76U_MCU_ROM_PATCH_OFFSET);122if (err < 0) {123err = -EIO;124goto out;125}126127mt76x2u_mcu_enable_patch(dev);128mt76x2u_mcu_reset_wmt(dev);129mdelay(20);130131if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 100)) {132dev_err(dev->mt76.dev, "failed to load ROM patch\n");133err = -ETIMEDOUT;134}135136out:137if (rom_protect)138mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1);139release_firmware(fw);140return err;141}142143static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev)144{145u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET;146const struct mt76x02_fw_header *hdr;147int err, len, ilm_len, dlm_len;148const struct firmware *fw;149150err = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev);151if (err < 0)152return err;153154if (!fw || !fw->data || fw->size < sizeof(*hdr)) {155err = -EINVAL;156goto out;157}158159hdr = (const struct mt76x02_fw_header *)fw->data;160ilm_len = le32_to_cpu(hdr->ilm_len);161dlm_len = le32_to_cpu(hdr->dlm_len);162len = sizeof(*hdr) + ilm_len + dlm_len;163if (fw->size != len) {164err = -EINVAL;165goto out;166}167168val = le16_to_cpu(hdr->fw_ver);169dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",170(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);171172val = le16_to_cpu(hdr->build_ver);173dev_info(dev->mt76.dev, "Build: %x\n", val);174dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);175176/* vendor reset */177mt76x02u_mcu_fw_reset(dev);178usleep_range(5000, 10000);179180/* enable USB_DMA_CFG */181val = MT_USB_DMA_CFG_RX_BULK_EN |182MT_USB_DMA_CFG_TX_BULK_EN |183FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20);184mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);185/* enable FCE to send in-band cmd */186mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);187/* FCE tx_fs_base_ptr */188mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);189/* FCE tx_fs_max_cnt */190mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 0x1);191/* FCE pdma enable */192mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);193/* FCE skip_fs_en */194mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);195196/* load ILM */197err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),198ilm_len, MCU_FW_URB_MAX_PAYLOAD,199MT76U_MCU_ILM_OFFSET);200if (err < 0) {201err = -EIO;202goto out;203}204205/* load DLM */206if (mt76xx_rev(dev) >= MT76XX_REV_E3)207dlm_offset += 0x800;208err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr) + ilm_len,209dlm_len, MCU_FW_URB_MAX_PAYLOAD,210dlm_offset);211if (err < 0) {212err = -EIO;213goto out;214}215216mt76x2u_mcu_load_ivb(dev);217if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 100)) {218dev_err(dev->mt76.dev, "firmware failed to start\n");219err = -ETIMEDOUT;220goto out;221}222223mt76_set(dev, MT_MCU_COM_REG0, BIT(1));224/* enable FCE to send in-band cmd */225mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);226mt76x02_set_ethtool_fwver(dev, hdr);227dev_dbg(dev->mt76.dev, "firmware running\n");228229out:230release_firmware(fw);231return err;232}233234int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev)235{236int err;237238err = mt76x2u_mcu_load_rom_patch(dev);239if (err < 0)240return err;241242return mt76x2u_mcu_load_firmware(dev);243}244245int mt76x2u_mcu_init(struct mt76x02_dev *dev)246{247int err;248249err = mt76x02_mcu_function_select(dev, Q_SELECT, 1);250if (err < 0)251return err;252253return mt76x02_mcu_set_radio_state(dev, true);254}255256257