usb_mcu.c (4135B)
1// SPDX-License-Identifier: ISC 2/* 3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 4 */ 5#include <linux/kernel.h> 6#include <linux/firmware.h> 7#include <linux/module.h> 8 9#include "mt76x0.h" 10#include "mcu.h" 11#include "../mt76x02_usb.h" 12 13#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 14#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) 15 16static int 17mt76x0u_upload_firmware(struct mt76x02_dev *dev, 18 const struct mt76x02_fw_header *hdr) 19{ 20 u8 *fw_payload = (u8 *)(hdr + 1); 21 u32 ilm_len, dlm_len; 22 void *ivb; 23 int err; 24 25 ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); 26 if (!ivb) 27 return -ENOMEM; 28 29 ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; 30 dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", 31 ilm_len, MT_MCU_IVB_SIZE); 32 err = mt76x02u_mcu_fw_send_data(dev, fw_payload + MT_MCU_IVB_SIZE, 33 ilm_len, MCU_FW_URB_MAX_PAYLOAD, 34 MT_MCU_IVB_SIZE); 35 if (err) 36 goto out; 37 38 dlm_len = le32_to_cpu(hdr->dlm_len); 39 dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); 40 err = mt76x02u_mcu_fw_send_data(dev, 41 fw_payload + le32_to_cpu(hdr->ilm_len), 42 dlm_len, MCU_FW_URB_MAX_PAYLOAD, 43 MT_MCU_DLM_OFFSET); 44 if (err) 45 goto out; 46 47 err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, 48 USB_DIR_OUT | USB_TYPE_VENDOR, 49 0x12, 0, ivb, MT_MCU_IVB_SIZE); 50 if (err < 0) 51 goto out; 52 53 if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { 54 dev_err(dev->mt76.dev, "Firmware failed to start\n"); 55 err = -ETIMEDOUT; 56 goto out; 57 } 58 59 dev_dbg(dev->mt76.dev, "Firmware running!\n"); 60 61out: 62 kfree(ivb); 63 64 return err; 65} 66 67static int mt76x0_get_firmware(struct mt76x02_dev *dev, 68 const struct firmware **fw) 69{ 70 int err; 71 72 /* try to load mt7610e fw if available 73 * otherwise fall back to mt7610u one 74 */ 75 err = firmware_request_nowarn(fw, MT7610E_FIRMWARE, dev->mt76.dev); 76 if (err) { 77 dev_info(dev->mt76.dev, "%s not found, switching to %s", 78 MT7610E_FIRMWARE, MT7610U_FIRMWARE); 79 return request_firmware(fw, MT7610U_FIRMWARE, 80 dev->mt76.dev); 81 } 82 return 0; 83} 84 85static int mt76x0u_load_firmware(struct mt76x02_dev *dev) 86{ 87 const struct firmware *fw; 88 const struct mt76x02_fw_header *hdr; 89 int len, ret; 90 u32 val; 91 92 mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | 93 MT_USB_DMA_CFG_TX_BULK_EN)); 94 95 if (mt76x0_firmware_running(dev)) 96 return 0; 97 98 ret = mt76x0_get_firmware(dev, &fw); 99 if (ret) 100 return ret; 101 102 if (!fw || !fw->data || fw->size < sizeof(*hdr)) 103 goto err_inv_fw; 104 105 hdr = (const struct mt76x02_fw_header *)fw->data; 106 107 if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) 108 goto err_inv_fw; 109 110 len = sizeof(*hdr); 111 len += le32_to_cpu(hdr->ilm_len); 112 len += le32_to_cpu(hdr->dlm_len); 113 114 if (fw->size != len) 115 goto err_inv_fw; 116 117 val = le16_to_cpu(hdr->fw_ver); 118 dev_dbg(dev->mt76.dev, 119 "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", 120 (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, 121 le16_to_cpu(hdr->build_ver), hdr->build_time); 122 123 len = le32_to_cpu(hdr->ilm_len); 124 125 mt76_wr(dev, 0x1004, 0x2c); 126 127 mt76_set(dev, MT_USB_DMA_CFG, 128 (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | 129 FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); 130 mt76x02u_mcu_fw_reset(dev); 131 usleep_range(5000, 6000); 132 133 mt76_wr(dev, MT_FCE_PSE_CTRL, 1); 134 135 /* FCE tx_fs_base_ptr */ 136 mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); 137 /* FCE tx_fs_max_cnt */ 138 mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); 139 /* FCE pdma enable */ 140 mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); 141 /* FCE skip_fs_en */ 142 mt76_wr(dev, MT_FCE_SKIP_FS, 3); 143 144 val = mt76_rr(dev, MT_USB_DMA_CFG); 145 val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; 146 mt76_wr(dev, MT_USB_DMA_CFG, val); 147 val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; 148 mt76_wr(dev, MT_USB_DMA_CFG, val); 149 150 ret = mt76x0u_upload_firmware(dev, hdr); 151 release_firmware(fw); 152 153 mt76_wr(dev, MT_FCE_PSE_CTRL, 1); 154 155 return ret; 156 157err_inv_fw: 158 dev_err(dev->mt76.dev, "Invalid firmware image\n"); 159 release_firmware(fw); 160 return -ENOENT; 161} 162 163int mt76x0u_mcu_init(struct mt76x02_dev *dev) 164{ 165 int ret; 166 167 ret = mt76x0u_load_firmware(dev); 168 if (ret < 0) 169 return ret; 170 171 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 172 173 return 0; 174}