1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017-2026 Morse Micro 4 */ 5 #include <linux/kernel.h> 6 #include <linux/firmware.h> 7 #include <linux/slab.h> 8 #include <linux/delay.h> 9 #include <linux/iopoll.h> 10 #include <linux/string_choices.h> 11 #include <net/mac80211.h> 12 #include <linux/elf.h> 13 #include <linux/crc32.h> 14 #include "fw.h" 15 #include "mac.h" 16 #include "bus.h" 17 18 /* 19 * Maximum wait time (microseconds) for firmware to boot (for host table 20 * pointer to be available) 21 */ 22 #define HOST_TABLE_PTR_POLL_TIMEOUT_US 1200000 23 #define HOST_TABLE_PTR_POLL_PERIOD_US 10000 24 25 /* Number of times to attempt flashing FW */ 26 #define FW_FLASH_ATTEMPT_COUNT 3 27 28 static int mm81x_fw_get_header(const u8 *data, Elf32_Ehdr *ehdr) 29 { 30 const struct mm81x_elf32_ehdr *p = 31 (const struct mm81x_elf32_ehdr *)data; 32 33 /* Magic check */ 34 if (p->e_ident[EI_MAG0] != ELFMAG0 || p->e_ident[EI_MAG1] != ELFMAG1 || 35 p->e_ident[EI_MAG2] != ELFMAG2 || p->e_ident[EI_MAG3] != ELFMAG3) 36 return -EINVAL; 37 38 /* elf32 and little endian */ 39 if (p->e_ident[EI_DATA] != ELFDATA2LSB || 40 p->e_ident[EI_CLASS] != ELFCLASS32) 41 return -EINVAL; 42 43 ehdr->e_phoff = le32_to_cpu(p->e_phoff); 44 ehdr->e_phentsize = le16_to_cpu(p->e_phentsize); 45 ehdr->e_phnum = le16_to_cpu(p->e_phnum); 46 ehdr->e_shoff = le32_to_cpu(p->e_shoff); 47 ehdr->e_shentsize = le16_to_cpu(p->e_shentsize); 48 ehdr->e_shnum = le16_to_cpu(p->e_shnum); 49 ehdr->e_shstrndx = le16_to_cpu(p->e_shstrndx); 50 ehdr->e_entry = le32_to_cpu(p->e_entry); 51 52 return 0; 53 } 54 55 static void mm81x_fw_parse_info(struct mm81x *mors, const u8 *data, int length) 56 { 57 const struct mm81x_fw_info_tlv *tlv = 58 (const struct mm81x_fw_info_tlv *)data; 59 60 while ((u8 *)tlv < (data + length)) { 61 switch (le16_to_cpu(tlv->type)) { 62 case MM81X_FW_INFO_TLV_BCF_ADDR: 63 mors->bcf_address = get_unaligned_le32(tlv->val); 64 break; 65 default: 66 break; 67 } 68 tlv = (const struct mm81x_fw_info_tlv *)((u8 *)tlv + 69 le16_to_cpu( 70 tlv->length) + 71 sizeof(*tlv)); 72 } 73 } 74 75 static int mm81x_fw_get_section_header(const u8 *data, Elf32_Ehdr *ehdr, 76 Elf32_Shdr *shdr, int i) 77 { 78 const struct mm81x_elf32_shdr *p = 79 (void *)(data + ehdr->e_shoff + (i * ehdr->e_shentsize)); 80 81 shdr->sh_name = le32_to_cpu(p->sh_name); 82 shdr->sh_type = le32_to_cpu(p->sh_type); 83 shdr->sh_offset = le32_to_cpu(p->sh_offset); 84 shdr->sh_addr = le32_to_cpu(p->sh_addr); 85 shdr->sh_size = le32_to_cpu(p->sh_size); 86 shdr->sh_flags = le32_to_cpu(p->sh_flags); 87 88 return 0; 89 } 90 91 static int mm81x_fw_set_boot_addr(struct mm81x *mors, uint32_t addr) 92 { 93 int status; 94 95 dev_dbg(mors->dev, "Overwriting boot address to 0x%x", addr); 96 mm81x_claim_bus(mors); 97 status = mm81x_reg32_write(mors, MM81X_REG_BOOT_ADDR(mors), addr); 98 mm81x_release_bus(mors); 99 return status; 100 } 101 102 static int mm81x_fw_load_fw(struct mm81x *mors, const struct firmware *fw) 103 { 104 int i; 105 int ret = 0; 106 Elf32_Ehdr ehdr; 107 Elf32_Phdr phdr; 108 Elf32_Shdr shdr; 109 Elf32_Shdr sh_strtab; 110 const char *sh_strs; 111 112 u8 *fw_buf = devm_kmalloc(mors->dev, ROUND_BYTES_TO_WORD(fw->size), 113 GFP_KERNEL); 114 115 if (!fw_buf) 116 return -ENOMEM; 117 118 if (mm81x_fw_get_header(fw->data, &ehdr)) { 119 dev_err(mors->dev, "Wrong file format"); 120 return -EINVAL; 121 } 122 123 if (mm81x_fw_get_section_header(fw->data, &ehdr, &sh_strtab, 124 ehdr.e_shstrndx)) { 125 dev_err(mors->dev, "Invalid firmware. Missing string table"); 126 return -ENOENT; 127 } 128 129 sh_strs = (const char *)fw->data + sh_strtab.sh_offset; 130 131 for (i = 0; i < ehdr.e_phnum; i++) { 132 int status; 133 int address; 134 const struct mm81x_elf32_phdr *p = 135 (void *)(fw->data + ehdr.e_phoff + 136 i * ehdr.e_phentsize); 137 138 phdr.p_type = le32_to_cpu(p->p_type); 139 phdr.p_offset = le32_to_cpu(p->p_offset); 140 phdr.p_paddr = le32_to_cpu(p->p_paddr); 141 phdr.p_filesz = le32_to_cpu(p->p_filesz); 142 phdr.p_memsz = le32_to_cpu(p->p_memsz); 143 144 address = phdr.p_paddr; 145 146 if (phdr.p_type != PT_LOAD || !phdr.p_memsz) 147 continue; 148 149 if (phdr.p_filesz && phdr.p_offset && 150 (phdr.p_offset + phdr.p_filesz) < fw->size) { 151 u32 padded_size = ROUND_BYTES_TO_WORD(phdr.p_filesz); 152 153 memcpy(fw_buf, fw->data + phdr.p_offset, padded_size); 154 /* Set padding to 0xff */ 155 memset(fw_buf + phdr.p_filesz, 0xff, 156 padded_size - phdr.p_filesz); 157 mm81x_claim_bus(mors); 158 status = mm81x_dm_write(mors, address, fw_buf, 159 padded_size); 160 mm81x_release_bus(mors); 161 if (status) { 162 ret = -EIO; 163 break; 164 } 165 } 166 } 167 168 for (i = 0; i < ehdr.e_shnum; i++) { 169 if (mm81x_fw_get_section_header(fw->data, &ehdr, &shdr, i)) 170 continue; 171 172 /* This is the firmware info. Parse it */ 173 if (!strncmp(sh_strs + shdr.sh_name, ".fw_info", 174 sizeof(".fw_info"))) 175 mm81x_fw_parse_info(mors, fw->data + shdr.sh_offset, 176 shdr.sh_size); 177 } 178 179 if (ehdr.e_entry) 180 ret = mm81x_fw_set_boot_addr(mors, ehdr.e_entry); 181 182 devm_kfree(mors->dev, fw_buf); 183 return ret; 184 } 185 186 static int __mm81x_fw_load_bcf(struct mm81x *mors, unsigned int addr, 187 const void *src, size_t src_len, u8 *scratch, 188 size_t scratch_cap) 189 { 190 size_t rounded = ROUND_BYTES_TO_WORD(src_len); 191 int st; 192 193 if (rounded > scratch_cap) 194 return -EINVAL; 195 if (rounded > BCF_DATABASE_SIZE) 196 return -EFBIG; 197 198 memcpy(scratch, src, src_len); 199 if (rounded > src_len) 200 memset(scratch + src_len, 0xff, rounded - src_len); 201 202 mm81x_claim_bus(mors); 203 st = mm81x_dm_write(mors, addr, scratch, rounded); 204 mm81x_release_bus(mors); 205 206 return st ? -EIO : 0; 207 } 208 209 static int mm81x_fw_load_bcf(struct mm81x *mors, const struct firmware *bcf, 210 unsigned int bcf_address) 211 { 212 int i, ret = 0; 213 size_t reg_prefix_len, cfg_len_rounded = 0, reg_len_rounded; 214 Elf32_Ehdr ehdr; 215 Elf32_Shdr shdr, sh_strtab; 216 const char *sh_strs, *reg_prefix = ".regdom_", *reg_src; 217 size_t reg_len; 218 u8 *bcf_buf; 219 220 bcf_buf = devm_kmalloc(mors->dev, ROUND_BYTES_TO_WORD(bcf->size), 221 GFP_KERNEL); 222 if (!bcf_buf) 223 return -ENOMEM; 224 225 if (mm81x_fw_get_header(bcf->data, &ehdr)) { 226 dev_err(mors->dev, "Wrong file format"); 227 ret = -EINVAL; 228 goto out_free; 229 } 230 231 if (mm81x_fw_get_section_header(bcf->data, &ehdr, &sh_strtab, 232 ehdr.e_shstrndx)) { 233 dev_err(mors->dev, "Invalid BCF - missing string table"); 234 ret = -ENOENT; 235 goto out_free; 236 } 237 238 sh_strs = (const char *)bcf->data + sh_strtab.sh_offset; 239 reg_prefix_len = strlen(reg_prefix); 240 241 for (i = 0; i < ehdr.e_shnum; i++) { 242 if (mm81x_fw_get_section_header(bcf->data, &ehdr, &shdr, i)) 243 continue; 244 if (strcmp(sh_strs + shdr.sh_name, ".board_config")) 245 continue; 246 247 cfg_len_rounded = ROUND_BYTES_TO_WORD(shdr.sh_size); 248 dev_dbg(mors->dev, 249 "Write BCF board_config - addr 0x%x size %zu", 250 bcf_address, cfg_len_rounded); 251 252 ret = __mm81x_fw_load_bcf(mors, bcf_address, 253 bcf->data + shdr.sh_offset, 254 shdr.sh_size, bcf_buf, 255 ROUND_BYTES_TO_WORD(bcf->size)); 256 if (ret) 257 goto out_free; 258 259 bcf_address += cfg_len_rounded; 260 break; 261 } 262 263 ret = -EINVAL; 264 for (; i < ehdr.e_shnum; i++) { 265 if (mm81x_fw_get_section_header(bcf->data, &ehdr, &shdr, i)) 266 continue; 267 if (strncmp(sh_strs + shdr.sh_name, reg_prefix, reg_prefix_len)) 268 continue; 269 if (strncmp(sh_strs + shdr.sh_name + reg_prefix_len, 270 mors->country, 2)) 271 continue; 272 273 reg_src = bcf->data + shdr.sh_offset; 274 reg_len = shdr.sh_size; 275 dev_dbg(mors->dev, "Write BCF %s - addr 0x%x size %zu", 276 sh_strs + shdr.sh_name, bcf_address, 277 ROUND_BYTES_TO_WORD(reg_len)); 278 ret = 0; 279 break; 280 } 281 282 if (ret) 283 goto out_free; 284 285 reg_len_rounded = ROUND_BYTES_TO_WORD(reg_len); 286 if ((cfg_len_rounded + reg_len_rounded) > BCF_DATABASE_SIZE) { 287 ret = -EFBIG; 288 goto out_free; 289 } 290 291 ret = __mm81x_fw_load_bcf(mors, bcf_address, reg_src, reg_len, bcf_buf, 292 ROUND_BYTES_TO_WORD(bcf->size)); 293 294 out_free: 295 devm_kfree(mors->dev, bcf_buf); 296 return ret; 297 } 298 299 static void mm81x_fw_clear_aon(struct mm81x *mors) 300 { 301 int idx; 302 u8 count = MM81X_REG_AON_COUNT(mors); 303 u32 address = MM81X_REG_AON_ADDR(mors); 304 305 for (idx = 0; idx < count; idx++, address += 4) { 306 if (mors->bus_type == MM81X_BUS_TYPE_USB && idx == 0) 307 /* Keep the USB power domain enabled in AON. */ 308 mm81x_reg32_write(mors, address, 309 MM81X_REG_AON_USB_RESET(mors)); 310 else 311 /* clear AON */ 312 mm81x_reg32_write(mors, address, 0x0); 313 } 314 315 mm81x_hw_toggle_aon_latch(mors); 316 } 317 318 static void mm81x_fw_trigger(struct mm81x *mors) 319 { 320 const unsigned int wait_after_msi_trigger_ms = 1; 321 322 mm81x_claim_bus(mors); 323 /* 324 * If not coming from a full reset, some AON flags may be latched. 325 * Make sure to clear any hanging AON bits (can affect booting). 326 */ 327 mm81x_fw_clear_aon(mors); 328 329 if (MM81X_REG_CLK_CTRL(mors)) 330 mm81x_reg32_write(mors, MM81X_REG_CLK_CTRL(mors), 331 MM81X_REG_CLK_CTRL_VALUE(mors)); 332 333 mm81x_reg32_write(mors, MM81X_REG_MSI(mors), 334 MM81X_REG_MSI_HOST_INT(mors)); 335 mm81x_release_bus(mors); 336 337 /* Give the chip a chance to boot */ 338 mdelay(wait_after_msi_trigger_ms); 339 } 340 341 static int mm81x_fw_verify_magic(struct mm81x *mors) 342 { 343 int ret = 0; 344 int magic = ~MM81X_REG_HOST_MAGIC_VALUE(mors); 345 346 mm81x_claim_bus(mors); 347 mm81x_reg32_read(mors, 348 mors->host_table_ptr + 349 offsetof(struct host_table, magic_number), 350 &magic); 351 352 if (magic != MM81X_REG_HOST_MAGIC_VALUE(mors)) { 353 dev_err(mors->dev, "FW magic mismatch 0x%08x:0x%08x", 354 MM81X_REG_HOST_MAGIC_VALUE(mors), magic); 355 ret = -EIO; 356 } 357 358 mm81x_release_bus(mors); 359 return ret; 360 } 361 362 static int mm81x_fw_get_flags(struct mm81x *mors) 363 { 364 int ret = 0; 365 int fw_flags = 0; 366 367 mm81x_claim_bus(mors); 368 ret = mm81x_reg32_read(mors, 369 mors->host_table_ptr + 370 offsetof(struct host_table, fw_flags), 371 &fw_flags); 372 mors->fw_flags = fw_flags; 373 mm81x_release_bus(mors); 374 375 return ret; 376 } 377 378 static int mm81x_fw_check_compatibility(struct mm81x *mors) 379 { 380 int ret = 0; 381 u32 fw_version; 382 u32 major; 383 u32 minor; 384 u32 patch; 385 386 mm81x_claim_bus(mors); 387 ret = mm81x_reg32_read(mors, 388 mors->host_table_ptr + 389 offsetof(struct host_table, 390 fw_version_number), 391 &fw_version); 392 mm81x_release_bus(mors); 393 394 major = MM81X_SEMVER_GET_MAJOR(fw_version); 395 minor = MM81X_SEMVER_GET_MINOR(fw_version); 396 patch = MM81X_SEMVER_GET_PATCH(fw_version); 397 398 /* Firmware on device must match the firmware file we requested */ 399 if (ret == 0 && major != mors->fw_major) { 400 dev_err(mors->dev, 401 "Incompatible FW version: (Requested) v%u, (Chip) %d.%d.%d\n", 402 mors->fw_major, major, minor, patch); 403 ret = -EPERM; 404 } else if (ret == 0 && major != HOST_CMD_SEMVER_MAJOR) { 405 dev_warn( 406 mors->dev, 407 "Running FW v%d.%d.%d, driver supports up to v%d, some features might not be supported", 408 major, minor, patch, HOST_CMD_SEMVER_MAJOR); 409 } else if (ret == 0 && minor != HOST_CMD_SEMVER_MINOR) { 410 dev_warn( 411 mors->dev, 412 "FW version mismatch, some features might not be supported: (Driver) %d.%d.%d, (Chip) %d.%d.%d", 413 HOST_CMD_SEMVER_MAJOR, HOST_CMD_SEMVER_MINOR, 414 HOST_CMD_SEMVER_PATCH, major, minor, patch); 415 } 416 417 return ret; 418 } 419 420 static int mm81x_fw_invalidate_host_ptr(struct mm81x *mors) 421 { 422 int ret; 423 424 mors->host_table_ptr = 0; 425 mm81x_claim_bus(mors); 426 ret = mm81x_reg32_write(mors, MM81X_REG_HOST_MANIFEST_PTR(mors), 0); 427 mm81x_release_bus(mors); 428 return ret; 429 } 430 431 static int mm81x_fw_get_host_table_ptr(struct mm81x *mors) 432 { 433 int ret, err; 434 435 mm81x_claim_bus(mors); 436 ret = read_poll_timeout(mm81x_reg32_read, err, 437 err || mors->host_table_ptr, 438 HOST_TABLE_PTR_POLL_PERIOD_US, 439 HOST_TABLE_PTR_POLL_TIMEOUT_US, false, mors, 440 MM81X_REG_HOST_MANIFEST_PTR(mors), 441 &mors->host_table_ptr); 442 mm81x_release_bus(mors); 443 444 return ret ? ret : err; 445 } 446 447 static int mm81x_fw_read_ext_host_table(struct mm81x *mors, 448 struct ext_host_tbl **ext_host_table) 449 { 450 int ret = 0; 451 u32 host_tbl_ptr = mors->host_table_ptr; 452 u32 ext_host_tbl_ptr; 453 u32 ext_host_tbl_ptr_addr = 454 host_tbl_ptr + offsetof(struct host_table, ext_host_tbl_addr); 455 u32 ext_host_tbl_len; 456 u32 ext_host_tbl_len_ptr_addr; 457 struct ext_host_tbl *host_tbl = NULL; 458 459 mm81x_claim_bus(mors); 460 ret = mm81x_reg32_read(mors, ext_host_tbl_ptr_addr, &ext_host_tbl_ptr); 461 if (ret) 462 goto exit; 463 464 if (!ext_host_tbl_ptr) { 465 ret = -ENXIO; 466 goto exit; 467 } 468 469 ext_host_tbl_len_ptr_addr = 470 ext_host_tbl_ptr + 471 offsetof(struct ext_host_tbl, ext_host_tbl_length); 472 473 ret = mm81x_reg32_read(mors, ext_host_tbl_len_ptr_addr, 474 &ext_host_tbl_len); 475 if (ret) 476 goto exit; 477 478 ext_host_tbl_len = ROUND_BYTES_TO_WORD(ext_host_tbl_len); 479 if (WARN_ON(ext_host_tbl_len == 0 || ext_host_tbl_len > INT_MAX)) { 480 ret = -EINVAL; 481 goto exit; 482 } 483 484 host_tbl = kmalloc(ext_host_tbl_len, GFP_KERNEL); 485 if (!host_tbl) { 486 ret = -ENOMEM; 487 goto exit; 488 } 489 490 ret = mm81x_dm_read(mors, ext_host_tbl_ptr, (u8 *)host_tbl, 491 (int)ext_host_tbl_len); 492 if (ret) 493 goto exit; 494 495 mm81x_release_bus(mors); 496 *ext_host_table = host_tbl; 497 return ret; 498 499 exit: 500 mm81x_release_bus(mors); 501 kfree(host_tbl); 502 return ret; 503 } 504 505 static void mm81x_fw_update_capabilities(struct mm81x *mors, 506 struct ext_host_tbl_s1g_caps *caps) 507 { 508 int i; 509 510 for (i = 0; i < FW_CAPABILITIES_FLAGS_WIDTH; i++) { 511 mors->fw_caps.flags[i] = le32_to_cpu(caps->flags[i]); 512 dev_dbg(mors->dev, "Firmware Manifest Flags%d: 0x%x", i, 513 le32_to_cpu(caps->flags[i])); 514 } 515 mors->fw_caps.ampdu_mss = caps->ampdu_mss; 516 mors->fw_caps.mm81x_mmss_offset = caps->mm81x_mmss_offset; 517 mors->fw_caps.beamformee_sts_capability = 518 caps->beamformee_sts_capability; 519 mors->fw_caps.maximum_ampdu_length_exponent = 520 caps->maximum_ampdu_length; 521 mors->fw_caps.number_sounding_dimensions = 522 caps->number_sounding_dimensions; 523 524 dev_dbg(mors->dev, "\tAMPDU Minimum start spacing: %u", 525 caps->ampdu_mss); 526 dev_dbg(mors->dev, "\tMorse Minimum Start Spacing offset: %u", 527 caps->mm81x_mmss_offset); 528 dev_dbg(mors->dev, "\tBeamformee STS Capability: %u", 529 caps->beamformee_sts_capability); 530 dev_dbg(mors->dev, "\tNumber of Sounding Dimensions: %u", 531 caps->number_sounding_dimensions); 532 dev_dbg(mors->dev, "\tMaximum AMPDU Length Exponent: %u", 533 caps->maximum_ampdu_length); 534 } 535 536 static void mm81x_fw_update_validate_skb_checksum( 537 struct mm81x *mors, 538 struct ext_host_tbl_insert_skb_checksum *validate_checksum) 539 { 540 mors->hif.validate_skb_checksum = 541 validate_checksum->insert_and_validate_checksum; 542 dev_dbg(mors->dev, "Validate checksum inserted by fw %s", 543 str_enabled_disabled(mors->hif.validate_skb_checksum)); 544 } 545 546 int mm81x_fw_parse_ext_host_tbl(struct mm81x *mors) 547 { 548 int ret; 549 u8 *head; 550 u8 *end; 551 struct ext_host_tbl *ext_host_table = NULL; 552 553 ret = mm81x_fw_read_ext_host_table(mors, &ext_host_table); 554 if (ret || !ext_host_table) 555 goto exit; 556 557 /* Parse the TLVs */ 558 head = ext_host_table->ext_host_table_data_tlvs; 559 end = ((u8 *)ext_host_table) + 560 le32_to_cpu(ext_host_table->ext_host_tbl_length); 561 562 while (head < end) { 563 struct ext_host_tbl_tlv_hdr *hdr = 564 (struct ext_host_tbl_tlv_hdr *)head; 565 566 switch (le16_to_cpu(hdr->tag)) { 567 case MM81X_FW_HOST_TABLE_TAG_S1G_CAPABILITIES: 568 mm81x_fw_update_capabilities( 569 mors, (struct ext_host_tbl_s1g_caps *)hdr); 570 break; 571 572 case MM81X_FW_HOST_TABLE_TAG_INSERT_SKB_CHECKSUM: 573 mm81x_fw_update_validate_skb_checksum( 574 mors, 575 (struct ext_host_tbl_insert_skb_checksum *)hdr); 576 break; 577 578 case MM81X_FW_HOST_TABLE_TAG_YAPS_TABLE: 579 mm81x_yaps_hw_read_table( 580 mors, &((struct ext_host_tbl_yaps_table *)hdr) 581 ->yaps_table); 582 break; 583 default: 584 break; 585 } 586 587 head += le16_to_cpu(hdr->length); 588 if (!hdr->length) 589 break; 590 } 591 592 kfree(ext_host_table); 593 return ret; 594 exit: 595 dev_err(mors->dev, "failed to parse ext host table %d", ret); 596 return ret; 597 } 598 599 static int __mm81x_fw_flash(struct mm81x *mors, const struct firmware *fw, 600 const struct firmware *bcf, bool reset) 601 { 602 int ret; 603 604 if (reset || !mors->chip_was_reset) { 605 ret = mm81x_hw_digital_reset(mors); 606 if (ret) 607 return ret; 608 } 609 610 mm81x_hw_pre_firmware_ndr_hook(mors); 611 612 ret = mm81x_fw_invalidate_host_ptr(mors); 613 if (ret) 614 return ret; 615 616 ret = mm81x_fw_load_fw(mors, fw); 617 if (ret) 618 return ret; 619 620 ret = mm81x_fw_load_bcf(mors, bcf, mors->bcf_address); 621 if (ret) 622 return ret; 623 624 mm81x_fw_trigger(mors); 625 mm81x_hw_post_firmware_ndr_hook(mors); 626 627 ret = mm81x_fw_get_host_table_ptr(mors); 628 if (ret) 629 return ret; 630 631 ret = mm81x_fw_verify_magic(mors); 632 if (ret) 633 return ret; 634 635 return mm81x_fw_check_compatibility(mors); 636 } 637 638 static int mm81x_fw_flash(struct mm81x *mors, const struct firmware *fw, 639 const struct firmware *bcf, bool reset) 640 { 641 int ret; 642 int retries = FW_FLASH_ATTEMPT_COUNT; 643 644 while (retries--) { 645 ret = __mm81x_fw_flash(mors, fw, bcf, reset); 646 if (!ret) 647 return 0; 648 649 mors->chip_was_reset = false; 650 } 651 652 return ret; 653 } 654 655 static uint32_t binary_crc(const struct firmware *fw) 656 { 657 return ~crc32_le(~0, (unsigned char const *)fw->data, fw->size) & 658 0xffffffff; 659 } 660 661 static int mm81x_fw_request(struct mm81x *mors, const struct firmware **fw) 662 { 663 int ret = -ENOENT; 664 int ver; 665 char *fw_path; 666 667 for (ver = MM81X_FW_VER_MAX; ver >= MM81X_FW_VER_MIN; ver--) { 668 fw_path = mm81x_core_get_fw_path(mors->chip_id, ver); 669 if (!fw_path) 670 return -ENOMEM; 671 672 ret = firmware_request_nowarn(fw, fw_path, mors->dev); 673 if (!ret) { 674 dev_info( 675 mors->dev, 676 "Loaded firmware from %s, size %zu, crc32 0x%08x\n", 677 fw_path, (*fw)->size, binary_crc(*fw)); 678 mors->fw_major = ver; 679 } 680 681 kfree(fw_path); 682 if (!ret) 683 return 0; 684 } 685 686 dev_err(mors->dev, "no firmware found (tried v%d down to v%d): %d\n", 687 MM81X_FW_VER_MAX, MM81X_FW_VER_MIN, ret); 688 return ret; 689 } 690 691 int mm81x_fw_init(struct mm81x *mors, bool reset) 692 { 693 int ret; 694 int board_id; 695 char *bcf_path = NULL; 696 const struct firmware *fw = NULL; 697 const struct firmware *bcf = NULL; 698 699 board_id = mm81x_hw_otp_get_board_type(mors); 700 701 if (!mm81x_hw_otp_valid_board_type(board_id)) { 702 dev_err(mors->dev, 703 "OTP not set, unable to determine BCF to use"); 704 ret = -EINVAL; 705 goto out; 706 } 707 708 dev_dbg(mors->dev, "Using board type 0x%04x from OTP", board_id); 709 710 ret = mm81x_fw_request(mors, &fw); 711 if (ret) 712 goto out; 713 714 bcf_path = kasprintf(GFP_KERNEL, 715 MM81X_FW_DIR 716 "/v%u/bcf_boardtype_%04x" MM81X_FW_EXT, 717 mors->fw_major, board_id); 718 if (!bcf_path) { 719 ret = -ENOMEM; 720 goto out; 721 } 722 723 ret = request_firmware(&bcf, bcf_path, mors->dev); 724 if (ret) { 725 if (ret == -ENOENT) 726 dev_err(mors->dev, "BCF %s not found\n", bcf_path); 727 goto out; 728 } 729 730 dev_info(mors->dev, "Loaded BCF from %s, size %zu, crc32 0x%08x\n", 731 bcf_path, bcf->size, binary_crc(bcf)); 732 733 ret = mm81x_fw_flash(mors, fw, bcf, reset); 734 if (ret) { 735 dev_err(mors->dev, "failed to flash firmware: %d", ret); 736 goto out; 737 } 738 739 ret = mm81x_fw_get_flags(mors); 740 741 out: 742 release_firmware(fw); 743 release_firmware(bcf); 744 kfree(bcf_path); 745 746 if (ret) 747 dev_err(mors->dev, "failed to init firmware: %d", ret); 748 else 749 dev_dbg(mors->dev, "firmware initialised"); 750 751 return ret; 752 } 753