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