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_mod_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 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 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 int catpt_store_memdumps(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 static int 175 catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) 176 { 177 struct catpt_stream_runtime *stream; 178 179 /* Lockless as no streams can be added or removed during D3 -> D0 transition. */ 180 list_for_each_entry(stream, &cdev->stream_list, node) { 181 u32 off, size; 182 int ret; 183 184 off = stream->persistent->start; 185 size = resource_size(stream->persistent); 186 dev_dbg(cdev->dev, "restoring stream %d ctx: off 0x%08x size %d\n", 187 stream->info.stream_hw_id, off, size); 188 189 ret = catpt_dma_memcpy_todsp(cdev, chan, 190 cdev->lpe_base + off, 191 cdev->dxbuf_paddr + off, 192 ALIGN(size, 4)); 193 if (ret) { 194 dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret); 195 return ret; 196 } 197 } 198 199 return 0; 200 } 201 202 static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) 203 { 204 int i; 205 206 for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { 207 struct catpt_save_meminfo *info; 208 struct resource r = {}; 209 u32 off; 210 int ret; 211 212 info = &cdev->dx_ctx.meminfo[i]; 213 if (info->source != CATPT_DX_TYPE_MEMORY_DUMP) 214 continue; 215 216 off = catpt_to_host_offset(info->offset); 217 resource_set_range(&r, off, info->size); 218 if (!resource_contains(&cdev->dram, &r)) 219 continue; 220 221 dev_dbg(cdev->dev, "restoring memdump: off 0x%08x size %d\n", 222 off, info->size); 223 224 ret = catpt_dma_memcpy_todsp(cdev, chan, 225 cdev->lpe_base + off, 226 cdev->dxbuf_paddr + off, 227 ALIGN(info->size, 4)); 228 if (ret) { 229 dev_err(cdev->dev, "restore block failed: %d\n", ret); 230 return ret; 231 } 232 } 233 234 return 0; 235 } 236 237 static int catpt_restore_fwimage(struct catpt_dev *cdev, 238 struct dma_chan *chan, dma_addr_t paddr, 239 struct catpt_fw_block_hdr *blk) 240 { 241 struct resource r1 = {}; 242 int i; 243 244 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 245 blk, sizeof(*blk), false); 246 247 resource_set_range(&r1, cdev->dram.start + blk->ram_offset, blk->size); 248 /* advance to data area */ 249 paddr += sizeof(*blk); 250 251 for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { 252 struct catpt_save_meminfo *info; 253 struct resource common = {}; 254 struct resource r2 = {}; 255 u32 off; 256 int ret; 257 258 info = &cdev->dx_ctx.meminfo[i]; 259 if (info->source != CATPT_DX_TYPE_FW_IMAGE) 260 continue; 261 262 off = catpt_to_host_offset(info->offset); 263 resource_set_range(&r2, off, info->size); 264 if (!resource_contains(&cdev->dram, &r2)) 265 continue; 266 267 if (!resource_intersection(&r2, &r1, &common)) 268 continue; 269 /* calculate start offset of common data area */ 270 off = common.start - r1.start; 271 272 dev_dbg(cdev->dev, "restoring fwimage: %pr\n", &common); 273 274 ret = catpt_dma_memcpy_todsp(cdev, chan, common.start, 275 paddr + off, 276 resource_size(&common)); 277 if (ret) { 278 dev_err(cdev->dev, "memcpy todsp failed: %d\n", ret); 279 return ret; 280 } 281 } 282 283 return 0; 284 } 285 286 static int catpt_load_block(struct catpt_dev *cdev, 287 struct dma_chan *chan, dma_addr_t paddr, 288 struct catpt_fw_block_hdr *blk, bool alloc) 289 { 290 struct resource *sram, *res; 291 dma_addr_t dst_addr; 292 int ret; 293 294 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 295 blk, sizeof(*blk), false); 296 297 switch (blk->ram_type) { 298 case CATPT_RAM_TYPE_IRAM: 299 sram = &cdev->iram; 300 break; 301 default: 302 sram = &cdev->dram; 303 break; 304 } 305 306 dst_addr = sram->start + blk->ram_offset; 307 if (alloc) { 308 res = __request_region(sram, dst_addr, blk->size, NULL, 0); 309 if (!res) 310 return -EBUSY; 311 } 312 313 /* advance to data area */ 314 paddr += sizeof(*blk); 315 316 ret = catpt_dma_memcpy_todsp(cdev, chan, dst_addr, paddr, blk->size); 317 if (ret) { 318 dev_err(cdev->dev, "memcpy error: %d\n", ret); 319 __release_region(sram, dst_addr, blk->size); 320 } 321 322 return ret; 323 } 324 325 static int catpt_restore_basefw(struct catpt_dev *cdev, 326 struct dma_chan *chan, dma_addr_t paddr, 327 struct catpt_fw_mod_hdr *basefw) 328 { 329 u32 offset = sizeof(*basefw); 330 int ret, i; 331 332 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 333 basefw, sizeof(*basefw), false); 334 335 /* restore basefw image */ 336 for (i = 0; i < basefw->blocks; i++) { 337 struct catpt_fw_block_hdr *blk; 338 339 blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset); 340 341 switch (blk->ram_type) { 342 case CATPT_RAM_TYPE_IRAM: 343 ret = catpt_load_block(cdev, chan, paddr + offset, 344 blk, false); 345 break; 346 default: 347 ret = catpt_restore_fwimage(cdev, chan, paddr + offset, 348 blk); 349 break; 350 } 351 352 if (ret) { 353 dev_err(cdev->dev, "restore block failed: %d\n", ret); 354 return ret; 355 } 356 357 offset += sizeof(*blk) + blk->size; 358 } 359 360 /* then proceed with memory dumps */ 361 ret = catpt_restore_memdumps(cdev, chan); 362 if (ret) 363 dev_err(cdev->dev, "restore memdumps failed: %d\n", ret); 364 365 return ret; 366 } 367 368 static int catpt_restore_module(struct catpt_dev *cdev, 369 struct dma_chan *chan, dma_addr_t paddr, 370 struct catpt_fw_mod_hdr *mod) 371 { 372 u32 offset = sizeof(*mod); 373 int i; 374 375 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 376 mod, sizeof(*mod), false); 377 378 for (i = 0; i < mod->blocks; i++) { 379 struct catpt_fw_block_hdr *blk; 380 int ret; 381 382 blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); 383 384 switch (blk->ram_type) { 385 case CATPT_RAM_TYPE_INSTANCE: 386 /* restore module state */ 387 ret = catpt_dma_memcpy_todsp(cdev, chan, 388 cdev->lpe_base + blk->ram_offset, 389 cdev->dxbuf_paddr + blk->ram_offset, 390 ALIGN(blk->size, 4)); 391 break; 392 default: 393 ret = catpt_load_block(cdev, chan, paddr + offset, 394 blk, false); 395 break; 396 } 397 398 if (ret) { 399 dev_err(cdev->dev, "restore block failed: %d\n", ret); 400 return ret; 401 } 402 403 offset += sizeof(*blk) + blk->size; 404 } 405 406 return 0; 407 } 408 409 static int catpt_load_module(struct catpt_dev *cdev, 410 struct dma_chan *chan, dma_addr_t paddr, 411 struct catpt_fw_mod_hdr *mod) 412 { 413 struct catpt_module_type *type; 414 u32 offset = sizeof(*mod); 415 int i; 416 417 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 418 mod, sizeof(*mod), false); 419 420 type = &cdev->modules[mod->module_id]; 421 422 for (i = 0; i < mod->blocks; i++) { 423 struct catpt_fw_block_hdr *blk; 424 int ret; 425 426 blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); 427 428 ret = catpt_load_block(cdev, chan, paddr + offset, blk, true); 429 if (ret) { 430 dev_err(cdev->dev, "load block failed: %d\n", ret); 431 return ret; 432 } 433 434 /* 435 * Save state window coordinates - these will be 436 * used to capture module state on D0 exit. 437 */ 438 if (blk->ram_type == CATPT_RAM_TYPE_INSTANCE) { 439 type->state_offset = blk->ram_offset; 440 type->state_size = blk->size; 441 } 442 443 offset += sizeof(*blk) + blk->size; 444 } 445 446 /* init module type static info */ 447 type->loaded = true; 448 /* DSP expects address from module header substracted by 4 */ 449 type->entry_point = mod->entry_point - 4; 450 type->persistent_size = mod->persistent_size; 451 type->scratch_size = mod->scratch_size; 452 453 return 0; 454 } 455 456 static int catpt_restore_firmware(struct catpt_dev *cdev, 457 struct dma_chan *chan, dma_addr_t paddr, 458 struct catpt_fw_hdr *fw) 459 { 460 u32 offset = sizeof(*fw); 461 int i; 462 463 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 464 fw, sizeof(*fw), false); 465 466 for (i = 0; i < fw->modules; i++) { 467 struct catpt_fw_mod_hdr *mod; 468 int ret; 469 470 mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); 471 if (strncmp(fw->signature, mod->signature, 472 FW_SIGNATURE_SIZE)) { 473 dev_err(cdev->dev, "module signature mismatch\n"); 474 return -EINVAL; 475 } 476 477 if (mod->module_id > CATPT_MODID_LAST) 478 return -EINVAL; 479 480 switch (mod->module_id) { 481 case CATPT_MODID_BASE_FW: 482 ret = catpt_restore_basefw(cdev, chan, paddr + offset, 483 mod); 484 break; 485 default: 486 ret = catpt_restore_module(cdev, chan, paddr + offset, 487 mod); 488 break; 489 } 490 491 if (ret) { 492 dev_err(cdev->dev, "restore module failed: %d\n", ret); 493 return ret; 494 } 495 496 offset += sizeof(*mod) + mod->mod_size; 497 } 498 499 return 0; 500 } 501 502 static int catpt_load_firmware(struct catpt_dev *cdev, 503 struct dma_chan *chan, dma_addr_t paddr, 504 struct catpt_fw_hdr *fw) 505 { 506 u32 offset = sizeof(*fw); 507 int i; 508 509 print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, 510 fw, sizeof(*fw), false); 511 512 for (i = 0; i < fw->modules; i++) { 513 struct catpt_fw_mod_hdr *mod; 514 int ret; 515 516 mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); 517 if (strncmp(fw->signature, mod->signature, 518 FW_SIGNATURE_SIZE)) { 519 dev_err(cdev->dev, "module signature mismatch\n"); 520 return -EINVAL; 521 } 522 523 if (mod->module_id > CATPT_MODID_LAST) 524 return -EINVAL; 525 526 ret = catpt_load_module(cdev, chan, paddr + offset, mod); 527 if (ret) { 528 dev_err(cdev->dev, "load module failed: %d\n", ret); 529 return ret; 530 } 531 532 offset += sizeof(*mod) + mod->mod_size; 533 } 534 535 return 0; 536 } 537 538 static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, 539 const char *name, const char *signature, 540 bool restore) 541 { 542 struct catpt_fw_hdr *fw; 543 struct firmware *img; 544 dma_addr_t paddr; 545 void *vaddr; 546 int ret; 547 548 ret = request_firmware((const struct firmware **)&img, name, cdev->dev); 549 if (ret) 550 return ret; 551 552 fw = (struct catpt_fw_hdr *)img->data; 553 if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) { 554 dev_err(cdev->dev, "firmware signature mismatch\n"); 555 ret = -EINVAL; 556 goto release_fw; 557 } 558 559 vaddr = dma_alloc_coherent(cdev->dev, img->size, &paddr, GFP_KERNEL); 560 if (!vaddr) { 561 ret = -ENOMEM; 562 goto release_fw; 563 } 564 565 memcpy(vaddr, img->data, img->size); 566 fw = (struct catpt_fw_hdr *)vaddr; 567 if (restore) 568 ret = catpt_restore_firmware(cdev, chan, paddr, fw); 569 else 570 ret = catpt_load_firmware(cdev, chan, paddr, fw); 571 572 dma_free_coherent(cdev->dev, img->size, vaddr, paddr); 573 release_fw: 574 release_firmware(img); 575 return ret; 576 } 577 578 static int catpt_load_images(struct catpt_dev *cdev, bool restore) 579 { 580 struct dma_chan *chan; 581 int ret; 582 583 chan = catpt_dma_request_config_chan(cdev); 584 if (IS_ERR(chan)) 585 return PTR_ERR(chan); 586 587 ret = catpt_load_image(cdev, chan, cdev->spec->fw_name, 588 FW_SIGNATURE, restore); 589 if (ret) 590 goto release_dma_chan; 591 592 if (!restore) 593 goto release_dma_chan; 594 ret = catpt_restore_streams_context(cdev, chan); 595 if (ret) 596 dev_err(cdev->dev, "restore streams ctx failed: %d\n", ret); 597 release_dma_chan: 598 dma_release_channel(chan); 599 return ret; 600 } 601 602 int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) 603 { 604 int ret; 605 606 catpt_dsp_stall(cdev, true); 607 608 ret = catpt_load_images(cdev, restore); 609 if (ret) { 610 dev_err(cdev->dev, "load binaries failed: %d\n", ret); 611 return ret; 612 } 613 614 reinit_completion(&cdev->fw_ready); 615 catpt_dsp_stall(cdev, false); 616 617 ret = wait_for_completion_timeout(&cdev->fw_ready, 618 msecs_to_jiffies(FW_READY_TIMEOUT_MS)); 619 if (!ret) { 620 dev_err(cdev->dev, "firmware ready timeout\n"); 621 return -ETIMEDOUT; 622 /* Wake up does not mean FW is ready, an exception could occur. */ 623 } else if (!cdev->ipc.ready) { 624 return -EREMOTEIO; 625 } 626 627 /* update sram pg & clock once done booting */ 628 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 629 catpt_dsp_update_srampge(cdev, &cdev->iram, cdev->spec->iram_mask); 630 631 return catpt_dsp_update_lpclock(cdev); 632 } 633 634 int catpt_first_boot_firmware(struct catpt_dev *cdev) 635 { 636 struct resource *res; 637 int ret; 638 639 ret = catpt_boot_firmware(cdev, false); 640 if (ret) { 641 dev_err(cdev->dev, "basefw boot failed: %d\n", ret); 642 return ret; 643 } 644 645 /* restrict FW Core dump area */ 646 __request_region(&cdev->dram, 0, 0x200, NULL, 0); 647 /* restrict entire area following BASE_FW - highest offset in DRAM */ 648 for (res = cdev->dram.child; res->sibling; res = res->sibling) 649 ; 650 __request_region(&cdev->dram, res->end + 1, 651 cdev->dram.end - res->end, NULL, 0); 652 653 ret = catpt_ipc_get_mixer_stream_info(cdev, &cdev->mixer); 654 if (ret) 655 return CATPT_IPC_RET(ret); 656 657 ret = catpt_arm_stream_templates(cdev); 658 if (ret) { 659 dev_err(cdev->dev, "arm templates failed: %d\n", ret); 660 return ret; 661 } 662 663 /* update dram pg for scratch and restricted regions */ 664 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 665 666 return 0; 667 } 668