btmtk.c (6787B)
1// SPDX-License-Identifier: ISC 2/* Copyright (C) 2021 MediaTek Inc. 3 * 4 */ 5#include <linux/module.h> 6#include <linux/firmware.h> 7 8#include <net/bluetooth/bluetooth.h> 9#include <net/bluetooth/hci_core.h> 10 11#include "btmtk.h" 12 13#define VERSION "0.1" 14 15/* It is for mt79xx download rom patch*/ 16#define MTK_FW_ROM_PATCH_HEADER_SIZE 32 17#define MTK_FW_ROM_PATCH_GD_SIZE 64 18#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64 19#define MTK_SEC_MAP_COMMON_SIZE 12 20#define MTK_SEC_MAP_NEED_SEND_SIZE 52 21 22struct btmtk_patch_header { 23 u8 datetime[16]; 24 u8 platform[4]; 25 __le16 hwver; 26 __le16 swver; 27 __le32 magicnum; 28} __packed; 29 30struct btmtk_global_desc { 31 __le32 patch_ver; 32 __le32 sub_sys; 33 __le32 feature_opt; 34 __le32 section_num; 35} __packed; 36 37struct btmtk_section_map { 38 __le32 sectype; 39 __le32 secoffset; 40 __le32 secsize; 41 union { 42 __le32 u4SecSpec[13]; 43 struct { 44 __le32 dlAddr; 45 __le32 dlsize; 46 __le32 seckeyidx; 47 __le32 alignlen; 48 __le32 sectype; 49 __le32 dlmodecrctype; 50 __le32 crc; 51 __le32 reserved[6]; 52 } bin_info_spec; 53 }; 54} __packed; 55 56int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, 57 wmt_cmd_sync_func_t wmt_cmd_sync) 58{ 59 struct btmtk_hci_wmt_params wmt_params; 60 struct btmtk_global_desc *globaldesc = NULL; 61 struct btmtk_section_map *sectionmap; 62 const struct firmware *fw; 63 const u8 *fw_ptr; 64 const u8 *fw_bin_ptr; 65 int err, dlen, i, status; 66 u8 flag, first_block, retry; 67 u32 section_num, dl_size, section_offset; 68 u8 cmd[64]; 69 70 err = request_firmware(&fw, fwname, &hdev->dev); 71 if (err < 0) { 72 bt_dev_err(hdev, "Failed to load firmware file (%d)", err); 73 return err; 74 } 75 76 fw_ptr = fw->data; 77 fw_bin_ptr = fw_ptr; 78 globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE); 79 section_num = le32_to_cpu(globaldesc->section_num); 80 81 for (i = 0; i < section_num; i++) { 82 first_block = 1; 83 fw_ptr = fw_bin_ptr; 84 sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + 85 MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i); 86 87 section_offset = le32_to_cpu(sectionmap->secoffset); 88 dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize); 89 90 if (dl_size > 0) { 91 retry = 20; 92 while (retry > 0) { 93 cmd[0] = 0; /* 0 means legacy dl mode. */ 94 memcpy(cmd + 1, 95 fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + 96 MTK_FW_ROM_PATCH_GD_SIZE + 97 MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + 98 MTK_SEC_MAP_COMMON_SIZE, 99 MTK_SEC_MAP_NEED_SEND_SIZE + 1); 100 101 wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 102 wmt_params.status = &status; 103 wmt_params.flag = 0; 104 wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1; 105 wmt_params.data = &cmd; 106 107 err = wmt_cmd_sync(hdev, &wmt_params); 108 if (err < 0) { 109 bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 110 err); 111 goto err_release_fw; 112 } 113 114 if (status == BTMTK_WMT_PATCH_UNDONE) { 115 break; 116 } else if (status == BTMTK_WMT_PATCH_PROGRESS) { 117 msleep(100); 118 retry--; 119 } else if (status == BTMTK_WMT_PATCH_DONE) { 120 goto next_section; 121 } else { 122 bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)", 123 status); 124 err = -EIO; 125 goto err_release_fw; 126 } 127 } 128 129 fw_ptr += section_offset; 130 wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 131 wmt_params.status = NULL; 132 133 while (dl_size > 0) { 134 dlen = min_t(int, 250, dl_size); 135 if (first_block == 1) { 136 flag = 1; 137 first_block = 0; 138 } else if (dl_size - dlen <= 0) { 139 flag = 3; 140 } else { 141 flag = 2; 142 } 143 144 wmt_params.flag = flag; 145 wmt_params.dlen = dlen; 146 wmt_params.data = fw_ptr; 147 148 err = wmt_cmd_sync(hdev, &wmt_params); 149 if (err < 0) { 150 bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 151 err); 152 goto err_release_fw; 153 } 154 155 dl_size -= dlen; 156 fw_ptr += dlen; 157 } 158 } 159next_section: 160 continue; 161 } 162 /* Wait a few moments for firmware activation done */ 163 usleep_range(100000, 120000); 164 165err_release_fw: 166 release_firmware(fw); 167 168 return err; 169} 170EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx); 171 172int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, 173 wmt_cmd_sync_func_t wmt_cmd_sync) 174{ 175 struct btmtk_hci_wmt_params wmt_params; 176 const struct firmware *fw; 177 const u8 *fw_ptr; 178 size_t fw_size; 179 int err, dlen; 180 u8 flag, param; 181 182 err = request_firmware(&fw, fwname, &hdev->dev); 183 if (err < 0) { 184 bt_dev_err(hdev, "Failed to load firmware file (%d)", err); 185 return err; 186 } 187 188 /* Power on data RAM the firmware relies on. */ 189 param = 1; 190 wmt_params.op = BTMTK_WMT_FUNC_CTRL; 191 wmt_params.flag = 3; 192 wmt_params.dlen = sizeof(param); 193 wmt_params.data = ¶m; 194 wmt_params.status = NULL; 195 196 err = wmt_cmd_sync(hdev, &wmt_params); 197 if (err < 0) { 198 bt_dev_err(hdev, "Failed to power on data RAM (%d)", err); 199 goto err_release_fw; 200 } 201 202 fw_ptr = fw->data; 203 fw_size = fw->size; 204 205 /* The size of patch header is 30 bytes, should be skip */ 206 if (fw_size < 30) { 207 err = -EINVAL; 208 goto err_release_fw; 209 } 210 211 fw_size -= 30; 212 fw_ptr += 30; 213 flag = 1; 214 215 wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 216 wmt_params.status = NULL; 217 218 while (fw_size > 0) { 219 dlen = min_t(int, 250, fw_size); 220 221 /* Tell device the position in sequence */ 222 if (fw_size - dlen <= 0) 223 flag = 3; 224 else if (fw_size < fw->size - 30) 225 flag = 2; 226 227 wmt_params.flag = flag; 228 wmt_params.dlen = dlen; 229 wmt_params.data = fw_ptr; 230 231 err = wmt_cmd_sync(hdev, &wmt_params); 232 if (err < 0) { 233 bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 234 err); 235 goto err_release_fw; 236 } 237 238 fw_size -= dlen; 239 fw_ptr += dlen; 240 } 241 242 wmt_params.op = BTMTK_WMT_RST; 243 wmt_params.flag = 4; 244 wmt_params.dlen = 0; 245 wmt_params.data = NULL; 246 wmt_params.status = NULL; 247 248 /* Activate funciton the firmware providing to */ 249 err = wmt_cmd_sync(hdev, &wmt_params); 250 if (err < 0) { 251 bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); 252 goto err_release_fw; 253 } 254 255 /* Wait a few moments for firmware activation done */ 256 usleep_range(10000, 12000); 257 258err_release_fw: 259 release_firmware(fw); 260 261 return err; 262} 263EXPORT_SYMBOL_GPL(btmtk_setup_firmware); 264 265int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 266{ 267 struct sk_buff *skb; 268 long ret; 269 270 skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); 271 if (IS_ERR(skb)) { 272 ret = PTR_ERR(skb); 273 bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", 274 ret); 275 return ret; 276 } 277 kfree_skb(skb); 278 279 return 0; 280} 281EXPORT_SYMBOL_GPL(btmtk_set_bdaddr); 282 283MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 284MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>"); 285MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION); 286MODULE_VERSION(VERSION); 287MODULE_LICENSE("GPL"); 288MODULE_FIRMWARE(FIRMWARE_MT7622); 289MODULE_FIRMWARE(FIRMWARE_MT7663); 290MODULE_FIRMWARE(FIRMWARE_MT7668); 291MODULE_FIRMWARE(FIRMWARE_MT7961);