1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2020 Intel Corporation 4 // 5 // Author: Cezary Rojewski <cezary.rojewski@intel.com> 6 // 7 8 #include <linux/dma-mapping.h> 9 #include <linux/firmware.h> 10 #include <linux/ioport.h> 11 #include <linux/slab.h> 12 #include "core.h" 13 #include "registers.h" 14 15 /* FW load (200ms) plus operational delays */ 16 #define FW_READY_TIMEOUT_MS 250 17 18 #define FW_SIGNATURE "$SST" 19 #define FW_SIGNATURE_SIZE 4 20 21 struct catpt_fw_hdr { 22 char signature[FW_SIGNATURE_SIZE]; 23 u32 file_size; 24 u32 modules; 25 u32 file_format; 26 u32 reserved[4]; 27 } __packed; 28 29 struct catpt_fw_module_hdr { 30 char signature[FW_SIGNATURE_SIZE]; 31 u32 mod_size; 32 u32 blocks; 33 u16 slot; 34 u16 module_id; 35 u32 entry_point; 36 u32 persistent_size; 37 u32 scratch_size; 38 } __packed; 39 40 enum catpt_ram_type { 41 CATPT_RAM_TYPE_IRAM = 1, 42 CATPT_RAM_TYPE_DRAM = 2, 43 /* DRAM with module's initial state */ 44 CATPT_RAM_TYPE_INSTANCE = 3, 45 }; 46 47 struct catpt_fw_block_hdr { 48 u32 ram_type; 49 u32 size; 50 u32 ram_offset; 51 u32 rsvd; 52 } __packed; 53 54 void catpt_sram_free(struct resource *sram) 55 { 56 struct resource *res, *save; 57 58 for (res = sram->child; res;) { 59 save = res->sibling; 60 release_resource(res); 61 kfree(res); 62 res = save; 63 } 64 } 65 66 struct resource * 67 catpt_request_region(struct resource *root, resource_size_t size) 68 { 69 struct resource *res = root->child; 70 resource_size_t addr = root->start; 71 72 for (;;) { 73 if (res->start - addr >= size) 74 break; 75 addr = res->end + 1; 76 res = res->sibling; 77 if (!res) 78 return NULL; 79 } 80 81 return __request_region(root, addr, size, NULL, 0); 82 } 83 84 static int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) 85 { 86 struct catpt_stream_runtime *stream; 87 88 /* Lockless as no streams can be added or removed during D3 -> D0 transition. */ 89 list_for_each_entry(stream, &cdev->stream_list, node) { 90 u32 off, size; 91 int ret; 92 93 off = stream->persistent->start; 94 size = resource_size(stream->persistent); 95 dev_dbg(cdev->dev, "storing stream %d ctx: off 0x%08x size %d\n", 96 stream->info.stream_hw_id, off, size); 97 98 ret = catpt_dma_memcpy_fromdsp(cdev, chan, 99 cdev->dxbuf_paddr + off, 100 cdev->lpe_base + off, 101 ALIGN(size, 4)); 102 if (ret) { 103 dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret); 104 return ret; 105 } 106 } 107 108 return 0; 109 } 110 111 static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) 112 { 113 int i; 114 115 for (i = 0; i < ARRAY_SIZE(cdev->modules); i++) { 116 struct catpt_module_type *type; 117 u32 off; 118 int ret; 119 120 type = &cdev->modules[i]; 121 if (!type->loaded || !type->state_size) 122 continue; 123 124 off = type->state_offset; 125 dev_dbg(cdev->dev, "storing mod %d state: off 0x%08x size %d\n", 126 i, off, type->state_size); 127 128 ret = catpt_dma_memcpy_fromdsp(cdev, chan, 129 cdev->dxbuf_paddr + off, 130 cdev->lpe_base + off, 131 ALIGN(type->state_size, 4)); 132 if (ret) { 133 dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret); 134 return ret; 135 } 136 } 137 138 return 0; 139 } 140 141 static int catpt_store_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) 142 { 143 int i; 144 145 for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { 146 struct catpt_save_meminfo *info; 147 u32 off; 148 int ret; 149 150 info = &cdev->dx_ctx.meminfo[i]; 151 if (info->source != CATPT_DX_TYPE_MEMORY_DUMP) 152 continue; 153 154 off = catpt_to_host_offset(info->offset); 155 if (off < cdev->dram.start || off > cdev->dram.end) 156 continue; 157 158 dev_dbg(cdev->dev, "storing memdump: off 0x%08x size %d\n", 159 off, info->size); 160 161 ret = catpt_dma_memcpy_fromdsp(cdev, chan, 162 cdev->dxbuf_paddr + off, 163 cdev->lpe_base + off, 164 ALIGN(info->size, 4)); 165 if (ret) { 166 dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret); 167 return ret; 168 } 169 } 170 171 return 0; 172 } 173 174 int catpt_store_firmware_context(struct catpt_dev *cdev) 175 { 176 struct dma_chan *chan; 177 int ret; 178 179 chan = catpt_dma_request_config_chan(cdev); 180 if (IS_ERR(chan)) 181 return PTR_ERR(chan); 182 183 ret = catpt_dsp_stall(cdev, true); 184 if (ret) 185 goto exit; 186 187 ret = catpt_store_dram_data(cdev, chan); 188 if (ret) { 189 dev_err(cdev->dev, "store memdumps failed: %d\n", ret); 190 goto exit; 191 } 192 193 ret = catpt_store_module_states(cdev, chan); 194 if (ret) { 195 dev_err(cdev->dev, "store module states failed: %d\n", ret); 196 goto exit; 197 } 198 199 ret = catpt_store_streams_context(cdev, chan); 200 if (ret) 201 dev_err(cdev->dev, "store streams ctx failed: %d\n", ret); 202 exit: 203 dma_release_channel(chan); 204 return ret; 205 } 206 207 static int 208 catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) 209 { 210 struct catpt_stream_runtime *stream; 211 212 /* Lockless as no streams can be added or removed during D3 -> D0 transition. */ 213 list_for_each_entry(stream, &cdev->stream_list, node) { 214 u32 off, size; 215 int ret; 216 217 off = stream->persistent->start; 218 size = resource_size(stream->persistent); 219 dev_dbg(cdev->dev, "restoring stream %d ctx: off 0x%08x size %d\n", 220 stream->info.stream_hw_id, off, size); 221 222 ret = catpt_dma_memcpy_todsp(cdev, chan, 223 cdev->lpe_base + off, 224 cdev->dxbuf_paddr + off, 225 ALIGN(size, 4)); 226 if (ret) { 227 dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret); 228 return ret; 229 } 230 } 231 232 return 0; 233 } 234 235 static int catpt_restore_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) 236 { 237 int i; 238 239 for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { 240 struct catpt_save_meminfo *info; 241 struct resource r = {}; 242 u32 off; 243 int ret; 244 245 info = &cdev->dx_ctx.meminfo[i]; 246 if (info->source != CATPT_DX_TYPE_MEMORY_DUMP) 247 continue; 248 249 off = catpt_to_host_offset(info->offset); 250 resource_set_range(&r, off, info->size); 251 if (!resource_contains(&cdev->dram, &r)) 252 continue; 253 254 dev_dbg(cdev->dev, "restoring memdump: off 0x%08x size %d\n", 255 off, info->size); 256 257 ret = catpt_dma_memcpy_todsp(cdev, chan, 258 cdev->lpe_base + off, 259 cdev->dxbuf_paddr + off, 260 ALIGN(info->size, 4)); 261 if (ret) { 262 dev_err(cdev->dev, "restore block failed: %d\n", ret); 263 return ret; 264 } 265 } 266 267 return 0; 268 } 269 270 static int catpt_restore_dram_rodata(struct catpt_dev *cdev, 271 struct dma_chan *chan, dma_addr_t paddr, 272 struct catpt_fw_block_hdr *blk) 273 { 274 struct resource r1 = {}; 275 int i; 276 277 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 278 blk, sizeof(*blk), false); 279 280 resource_set_range(&r1, cdev->dram.start + blk->ram_offset, blk->size); 281 /* advance to data area */ 282 paddr += sizeof(*blk); 283 284 for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { 285 struct catpt_save_meminfo *info; 286 struct resource common = {}; 287 struct resource r2 = {}; 288 u32 off; 289 int ret; 290 291 info = &cdev->dx_ctx.meminfo[i]; 292 if (info->source != CATPT_DX_TYPE_FW_IMAGE) 293 continue; 294 295 off = catpt_to_host_offset(info->offset); 296 resource_set_range(&r2, off, info->size); 297 if (!resource_contains(&cdev->dram, &r2)) 298 continue; 299 300 if (!resource_intersection(&r2, &r1, &common)) 301 continue; 302 /* calculate start offset of common data area */ 303 off = common.start - r1.start; 304 305 dev_dbg(cdev->dev, "restoring fwimage: %pr\n", &common); 306 307 ret = catpt_dma_memcpy_todsp(cdev, chan, common.start, 308 paddr + off, 309 resource_size(&common)); 310 if (ret) { 311 dev_err(cdev->dev, "memcpy todsp failed: %d\n", ret); 312 return ret; 313 } 314 } 315 316 return 0; 317 } 318 319 static int catpt_load_block(struct catpt_dev *cdev, 320 struct dma_chan *chan, dma_addr_t paddr, 321 struct catpt_fw_block_hdr *blk, bool alloc) 322 { 323 struct resource *sram, *res; 324 dma_addr_t dst_addr; 325 int ret; 326 327 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 328 blk, sizeof(*blk), false); 329 330 switch (blk->ram_type) { 331 case CATPT_RAM_TYPE_IRAM: 332 sram = &cdev->iram; 333 break; 334 default: 335 sram = &cdev->dram; 336 break; 337 } 338 339 dst_addr = sram->start + blk->ram_offset; 340 if (alloc) { 341 res = __request_region(sram, dst_addr, blk->size, NULL, 0); 342 if (!res) 343 return -EBUSY; 344 } 345 346 /* advance to data area */ 347 paddr += sizeof(*blk); 348 349 ret = catpt_dma_memcpy_todsp(cdev, chan, dst_addr, paddr, blk->size); 350 if (ret) { 351 dev_err(cdev->dev, "memcpy error: %d\n", ret); 352 __release_region(sram, dst_addr, blk->size); 353 } 354 355 return ret; 356 } 357 358 static int catpt_restore_basefw(struct catpt_dev *cdev, 359 struct dma_chan *chan, dma_addr_t paddr, 360 struct catpt_fw_module_hdr *basefw) 361 { 362 u32 off = sizeof(*basefw); 363 int ret, i; 364 365 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 366 basefw, sizeof(*basefw), false); 367 368 /* Restore IRAM and .rodata for DRAM based on the firmware image. */ 369 for (i = 0; i < basefw->blocks; i++) { 370 struct catpt_fw_block_hdr *blk; 371 372 blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + off); 373 374 switch (blk->ram_type) { 375 case CATPT_RAM_TYPE_IRAM: 376 ret = catpt_load_block(cdev, chan, paddr + off, blk, false); 377 break; 378 default: 379 ret = catpt_restore_dram_rodata(cdev, chan, paddr + off, blk); 380 break; 381 } 382 383 if (ret) { 384 dev_err(cdev->dev, "restore block failed: %d\n", ret); 385 return ret; 386 } 387 388 off += sizeof(*blk) + blk->size; 389 } 390 391 /* Then proceed with DRAM .data saved before D3. */ 392 ret = catpt_restore_dram_data(cdev, chan); 393 if (ret) 394 dev_err(cdev->dev, "restore memdumps failed: %d\n", ret); 395 396 return ret; 397 } 398 399 static int catpt_restore_module(struct catpt_dev *cdev, 400 struct dma_chan *chan, dma_addr_t paddr, 401 struct catpt_fw_module_hdr *mod) 402 { 403 u32 off = sizeof(*mod); 404 int i; 405 406 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 407 mod, sizeof(*mod), false); 408 409 for (i = 0; i < mod->blocks; i++) { 410 struct catpt_fw_block_hdr *blk; 411 int ret; 412 413 blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); 414 415 switch (blk->ram_type) { 416 case CATPT_RAM_TYPE_INSTANCE: 417 /* restore module state */ 418 ret = catpt_dma_memcpy_todsp(cdev, chan, 419 cdev->lpe_base + blk->ram_offset, 420 cdev->dxbuf_paddr + blk->ram_offset, 421 ALIGN(blk->size, 4)); 422 break; 423 default: 424 ret = catpt_load_block(cdev, chan, paddr + off, 425 blk, false); 426 break; 427 } 428 429 if (ret) { 430 dev_err(cdev->dev, "restore block failed: %d\n", ret); 431 return ret; 432 } 433 434 off += sizeof(*blk) + blk->size; 435 } 436 437 return 0; 438 } 439 440 static int catpt_load_module(struct catpt_dev *cdev, 441 struct dma_chan *chan, dma_addr_t paddr, 442 struct catpt_fw_module_hdr *mod) 443 { 444 struct catpt_module_type *type; 445 u32 off = sizeof(*mod); 446 int i; 447 448 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 449 mod, sizeof(*mod), false); 450 451 type = &cdev->modules[mod->module_id]; 452 453 for (i = 0; i < mod->blocks; i++) { 454 struct catpt_fw_block_hdr *blk; 455 int ret; 456 457 blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); 458 459 ret = catpt_load_block(cdev, chan, paddr + off, blk, true); 460 if (ret) { 461 dev_err(cdev->dev, "load block failed: %d\n", ret); 462 return ret; 463 } 464 465 /* 466 * Save state window coordinates - these will be 467 * used to capture module state on D0 exit. 468 */ 469 if (blk->ram_type == CATPT_RAM_TYPE_INSTANCE) { 470 type->state_offset = blk->ram_offset; 471 type->state_size = blk->size; 472 } 473 474 off += sizeof(*blk) + blk->size; 475 } 476 477 /* init module type static info */ 478 type->loaded = true; 479 /* DSP expects address from module header substracted by 4 */ 480 type->entry_point = mod->entry_point - 4; 481 type->persistent_size = mod->persistent_size; 482 type->scratch_size = mod->scratch_size; 483 484 return 0; 485 } 486 487 static int catpt_restore_firmware(struct catpt_dev *cdev, 488 struct dma_chan *chan, dma_addr_t paddr, 489 struct catpt_fw_hdr *fw) 490 { 491 u32 off = sizeof(*fw); 492 int i; 493 494 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 495 fw, sizeof(*fw), false); 496 497 for (i = 0; i < fw->modules; i++) { 498 struct catpt_fw_module_hdr *mod; 499 int ret; 500 501 mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); 502 if (strncmp(fw->signature, mod->signature, 503 FW_SIGNATURE_SIZE)) { 504 dev_err(cdev->dev, "module signature mismatch\n"); 505 return -EINVAL; 506 } 507 508 if (mod->module_id > CATPT_MODID_LAST) 509 return -EINVAL; 510 511 switch (mod->module_id) { 512 case CATPT_MODID_BASE_FW: 513 ret = catpt_restore_basefw(cdev, chan, paddr + off, mod); 514 break; 515 default: 516 ret = catpt_restore_module(cdev, chan, paddr + off, mod); 517 break; 518 } 519 520 if (ret) { 521 dev_err(cdev->dev, "restore module failed: %d\n", ret); 522 return ret; 523 } 524 525 off += sizeof(*mod) + mod->mod_size; 526 } 527 528 return 0; 529 } 530 531 static int catpt_load_firmware(struct catpt_dev *cdev, 532 struct dma_chan *chan, dma_addr_t paddr, 533 struct catpt_fw_hdr *fw) 534 { 535 u32 off = sizeof(*fw); 536 int i; 537 538 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 539 fw, sizeof(*fw), false); 540 541 for (i = 0; i < fw->modules; i++) { 542 struct catpt_fw_module_hdr *mod; 543 int ret; 544 545 mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); 546 if (strncmp(fw->signature, mod->signature, 547 FW_SIGNATURE_SIZE)) { 548 dev_err(cdev->dev, "module signature mismatch\n"); 549 return -EINVAL; 550 } 551 552 if (mod->module_id > CATPT_MODID_LAST) 553 return -EINVAL; 554 555 ret = catpt_load_module(cdev, chan, paddr + off, mod); 556 if (ret) { 557 dev_err(cdev->dev, "load module failed: %d\n", ret); 558 return ret; 559 } 560 561 off += sizeof(*mod) + mod->mod_size; 562 } 563 564 return 0; 565 } 566 567 static int catpt_request_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan, 568 const char *name, bool restore) 569 { 570 struct catpt_fw_hdr *fw; 571 struct firmware *img; 572 dma_addr_t paddr; 573 void *vaddr; 574 int ret; 575 576 ret = request_firmware((const struct firmware **)&img, name, cdev->dev); 577 if (ret) 578 return ret; 579 580 fw = (struct catpt_fw_hdr *)img->data; 581 if (strncmp(fw->signature, FW_SIGNATURE, FW_SIGNATURE_SIZE)) { 582 dev_err(cdev->dev, "firmware signature mismatch\n"); 583 ret = -EINVAL; 584 goto release_fw; 585 } 586 587 vaddr = dma_alloc_coherent(cdev->dev, img->size, &paddr, GFP_KERNEL); 588 if (!vaddr) { 589 ret = -ENOMEM; 590 goto release_fw; 591 } 592 593 memcpy(vaddr, img->data, img->size); 594 fw = (struct catpt_fw_hdr *)vaddr; 595 if (restore) 596 ret = catpt_restore_firmware(cdev, chan, paddr, fw); 597 else 598 ret = catpt_load_firmware(cdev, chan, paddr, fw); 599 600 dma_free_coherent(cdev->dev, img->size, vaddr, paddr); 601 release_fw: 602 release_firmware(img); 603 return ret; 604 } 605 606 static int catpt_request_dma_load_firmware(struct catpt_dev *cdev, bool restore) 607 { 608 struct dma_chan *chan; 609 int ret; 610 611 chan = catpt_dma_request_config_chan(cdev); 612 if (IS_ERR(chan)) 613 return PTR_ERR(chan); 614 615 ret = catpt_request_load_firmware(cdev, chan, cdev->spec->fw_name, restore); 616 if (ret) 617 goto release_dma_chan; 618 619 if (!restore) 620 goto release_dma_chan; 621 ret = catpt_restore_streams_context(cdev, chan); 622 if (ret) 623 dev_err(cdev->dev, "restore streams ctx failed: %d\n", ret); 624 release_dma_chan: 625 dma_release_channel(chan); 626 return ret; 627 } 628 629 int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) 630 { 631 int ret; 632 633 catpt_dsp_stall(cdev, true); 634 635 ret = catpt_request_dma_load_firmware(cdev, restore); 636 if (ret) { 637 dev_err(cdev->dev, "load binaries failed: %d\n", ret); 638 return ret; 639 } 640 641 reinit_completion(&cdev->fw_ready); 642 catpt_dsp_stall(cdev, false); 643 644 ret = wait_for_completion_timeout(&cdev->fw_ready, 645 msecs_to_jiffies(FW_READY_TIMEOUT_MS)); 646 if (!ret) { 647 dev_err(cdev->dev, "firmware ready timeout\n"); 648 return -ETIMEDOUT; 649 } 650 /* Wake up does not mean FW is ready, an exception could occur. */ 651 if (!cdev->ipc.ready) 652 return -EREMOTEIO; 653 654 /* update sram pg & clock once done booting */ 655 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 656 catpt_dsp_update_srampge(cdev, &cdev->iram, cdev->spec->iram_mask); 657 658 return catpt_dsp_update_lpclock(cdev); 659 } 660 661 int catpt_first_boot_firmware(struct catpt_dev *cdev) 662 { 663 struct resource *res; 664 int ret; 665 666 ret = catpt_boot_firmware(cdev, false); 667 if (ret) { 668 dev_err(cdev->dev, "basefw boot failed: %d\n", ret); 669 return ret; 670 } 671 672 /* restrict FW Core dump area */ 673 __request_region(&cdev->dram, 0, 0x200, NULL, 0); 674 /* restrict entire area following BASE_FW - highest offset in DRAM */ 675 for (res = cdev->dram.child; res->sibling; res = res->sibling) 676 ; 677 __request_region(&cdev->dram, res->end + 1, 678 cdev->dram.end - res->end, NULL, 0); 679 680 ret = catpt_ipc_get_mixer_stream_info(cdev, &cdev->mixer); 681 if (ret) 682 return CATPT_IPC_RET(ret); 683 684 ret = catpt_arm_stream_templates(cdev); 685 if (ret) { 686 dev_err(cdev->dev, "arm templates failed: %d\n", ret); 687 return ret; 688 } 689 690 /* update dram pg for scratch and restricted regions */ 691 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 692 693 return 0; 694 } 695