1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright(c) 2020 Intel Corporation. All rights reserved.
5 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
8 #include <linux/dma-mapping.h>
9 #include <linux/firmware.h>
10 #include <linux/slab.h>
12 #include "registers.h"
14 /* FW load (200ms) plus operational delays */
15 #define FW_READY_TIMEOUT_MS 250
17 #define FW_SIGNATURE "$SST"
18 #define FW_SIGNATURE_SIZE 4
21 char signature
[FW_SIGNATURE_SIZE
];
28 struct catpt_fw_mod_hdr
{
29 char signature
[FW_SIGNATURE_SIZE
];
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,
46 struct catpt_fw_block_hdr
{
53 void catpt_sram_init(struct resource
*sram
, u32 start
, u32 size
)
56 sram
->end
= start
+ size
- 1;
59 void catpt_sram_free(struct resource
*sram
)
61 struct resource
*res
, *save
;
63 for (res
= sram
->child
; res
;) {
65 release_resource(res
);
72 catpt_request_region(struct resource
*root
, resource_size_t size
)
74 struct resource
*res
= root
->child
;
75 resource_size_t addr
= root
->start
;
78 if (res
->start
- addr
>= size
)
86 return __request_region(root
, addr
, size
, NULL
, 0);
89 int catpt_store_streams_context(struct catpt_dev
*cdev
, struct dma_chan
*chan
)
91 struct catpt_stream_runtime
*stream
;
93 list_for_each_entry(stream
, &cdev
->stream_list
, node
) {
97 off
= stream
->persistent
->start
;
98 size
= resource_size(stream
->persistent
);
99 dev_dbg(cdev
->dev
, "storing stream %d ctx: off 0x%08x size %d\n",
100 stream
->info
.stream_hw_id
, off
, size
);
102 ret
= catpt_dma_memcpy_fromdsp(cdev
, chan
,
103 cdev
->dxbuf_paddr
+ off
,
104 cdev
->lpe_base
+ off
,
107 dev_err(cdev
->dev
, "memcpy fromdsp failed: %d\n", ret
);
115 int catpt_store_module_states(struct catpt_dev
*cdev
, struct dma_chan
*chan
)
119 for (i
= 0; i
< ARRAY_SIZE(cdev
->modules
); i
++) {
120 struct catpt_module_type
*type
;
124 type
= &cdev
->modules
[i
];
125 if (!type
->loaded
|| !type
->state_size
)
128 off
= type
->state_offset
;
129 dev_dbg(cdev
->dev
, "storing mod %d state: off 0x%08x size %d\n",
130 i
, off
, type
->state_size
);
132 ret
= catpt_dma_memcpy_fromdsp(cdev
, chan
,
133 cdev
->dxbuf_paddr
+ off
,
134 cdev
->lpe_base
+ off
,
135 ALIGN(type
->state_size
, 4));
137 dev_err(cdev
->dev
, "memcpy fromdsp failed: %d\n", ret
);
145 int catpt_store_memdumps(struct catpt_dev
*cdev
, struct dma_chan
*chan
)
149 for (i
= 0; i
< cdev
->dx_ctx
.num_meminfo
; i
++) {
150 struct catpt_save_meminfo
*info
;
154 info
= &cdev
->dx_ctx
.meminfo
[i
];
155 if (info
->source
!= CATPT_DX_TYPE_MEMORY_DUMP
)
158 off
= catpt_to_host_offset(info
->offset
);
159 if (off
< cdev
->dram
.start
|| off
> cdev
->dram
.end
)
162 dev_dbg(cdev
->dev
, "storing memdump: off 0x%08x size %d\n",
165 ret
= catpt_dma_memcpy_fromdsp(cdev
, chan
,
166 cdev
->dxbuf_paddr
+ off
,
167 cdev
->lpe_base
+ off
,
168 ALIGN(info
->size
, 4));
170 dev_err(cdev
->dev
, "memcpy fromdsp failed: %d\n", ret
);
179 catpt_restore_streams_context(struct catpt_dev
*cdev
, struct dma_chan
*chan
)
181 struct catpt_stream_runtime
*stream
;
183 list_for_each_entry(stream
, &cdev
->stream_list
, node
) {
187 off
= stream
->persistent
->start
;
188 size
= resource_size(stream
->persistent
);
189 dev_dbg(cdev
->dev
, "restoring stream %d ctx: off 0x%08x size %d\n",
190 stream
->info
.stream_hw_id
, off
, size
);
192 ret
= catpt_dma_memcpy_todsp(cdev
, chan
,
193 cdev
->lpe_base
+ off
,
194 cdev
->dxbuf_paddr
+ off
,
197 dev_err(cdev
->dev
, "memcpy fromdsp failed: %d\n", ret
);
205 static int catpt_restore_memdumps(struct catpt_dev
*cdev
, struct dma_chan
*chan
)
209 for (i
= 0; i
< cdev
->dx_ctx
.num_meminfo
; i
++) {
210 struct catpt_save_meminfo
*info
;
214 info
= &cdev
->dx_ctx
.meminfo
[i
];
215 if (info
->source
!= CATPT_DX_TYPE_MEMORY_DUMP
)
218 off
= catpt_to_host_offset(info
->offset
);
219 if (off
< cdev
->dram
.start
|| off
> cdev
->dram
.end
)
222 dev_dbg(cdev
->dev
, "restoring memdump: off 0x%08x size %d\n",
225 ret
= catpt_dma_memcpy_todsp(cdev
, chan
,
226 cdev
->lpe_base
+ off
,
227 cdev
->dxbuf_paddr
+ off
,
228 ALIGN(info
->size
, 4));
230 dev_err(cdev
->dev
, "restore block failed: %d\n", ret
);
238 static int catpt_restore_fwimage(struct catpt_dev
*cdev
,
239 struct dma_chan
*chan
, dma_addr_t paddr
,
240 struct catpt_fw_block_hdr
*blk
)
242 struct resource r1
, r2
, common
;
245 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
246 blk
, sizeof(*blk
), false);
248 r1
.start
= cdev
->dram
.start
+ blk
->ram_offset
;
249 r1
.end
= r1
.start
+ blk
->size
- 1;
250 /* advance to data area */
251 paddr
+= sizeof(*blk
);
253 for (i
= 0; i
< cdev
->dx_ctx
.num_meminfo
; i
++) {
254 struct catpt_save_meminfo
*info
;
258 info
= &cdev
->dx_ctx
.meminfo
[i
];
260 if (info
->source
!= CATPT_DX_TYPE_FW_IMAGE
)
263 off
= catpt_to_host_offset(info
->offset
);
264 if (off
< cdev
->dram
.start
|| off
> cdev
->dram
.end
)
268 r2
.end
= r2
.start
+ info
->size
- 1;
270 if (!resource_intersection(&r2
, &r1
, &common
))
272 /* calculate start offset of common data area */
273 off
= common
.start
- r1
.start
;
275 dev_dbg(cdev
->dev
, "restoring fwimage: %pr\n", &common
);
277 ret
= catpt_dma_memcpy_todsp(cdev
, chan
, common
.start
,
279 resource_size(&common
));
281 dev_err(cdev
->dev
, "memcpy todsp failed: %d\n", ret
);
289 static int catpt_load_block(struct catpt_dev
*cdev
,
290 struct dma_chan
*chan
, dma_addr_t paddr
,
291 struct catpt_fw_block_hdr
*blk
, bool alloc
)
293 struct resource
*sram
, *res
;
297 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
298 blk
, sizeof(*blk
), false);
300 switch (blk
->ram_type
) {
301 case CATPT_RAM_TYPE_IRAM
:
309 dst_addr
= sram
->start
+ blk
->ram_offset
;
311 res
= __request_region(sram
, dst_addr
, blk
->size
, NULL
, 0);
316 /* advance to data area */
317 paddr
+= sizeof(*blk
);
319 ret
= catpt_dma_memcpy_todsp(cdev
, chan
, dst_addr
, paddr
, blk
->size
);
321 dev_err(cdev
->dev
, "memcpy error: %d\n", ret
);
322 __release_region(sram
, dst_addr
, blk
->size
);
328 static int catpt_restore_basefw(struct catpt_dev
*cdev
,
329 struct dma_chan
*chan
, dma_addr_t paddr
,
330 struct catpt_fw_mod_hdr
*basefw
)
332 u32 offset
= sizeof(*basefw
);
335 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
336 basefw
, sizeof(*basefw
), false);
338 /* restore basefw image */
339 for (i
= 0; i
< basefw
->blocks
; i
++) {
340 struct catpt_fw_block_hdr
*blk
;
342 blk
= (struct catpt_fw_block_hdr
*)((u8
*)basefw
+ offset
);
344 switch (blk
->ram_type
) {
345 case CATPT_RAM_TYPE_IRAM
:
346 ret
= catpt_load_block(cdev
, chan
, paddr
+ offset
,
350 ret
= catpt_restore_fwimage(cdev
, chan
, paddr
+ offset
,
356 dev_err(cdev
->dev
, "restore block failed: %d\n", ret
);
360 offset
+= sizeof(*blk
) + blk
->size
;
363 /* then proceed with memory dumps */
364 ret
= catpt_restore_memdumps(cdev
, chan
);
366 dev_err(cdev
->dev
, "restore memdumps failed: %d\n", ret
);
371 static int catpt_restore_module(struct catpt_dev
*cdev
,
372 struct dma_chan
*chan
, dma_addr_t paddr
,
373 struct catpt_fw_mod_hdr
*mod
)
375 u32 offset
= sizeof(*mod
);
378 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
379 mod
, sizeof(*mod
), false);
381 for (i
= 0; i
< mod
->blocks
; i
++) {
382 struct catpt_fw_block_hdr
*blk
;
385 blk
= (struct catpt_fw_block_hdr
*)((u8
*)mod
+ offset
);
387 switch (blk
->ram_type
) {
388 case CATPT_RAM_TYPE_INSTANCE
:
389 /* restore module state */
390 ret
= catpt_dma_memcpy_todsp(cdev
, chan
,
391 cdev
->lpe_base
+ blk
->ram_offset
,
392 cdev
->dxbuf_paddr
+ blk
->ram_offset
,
393 ALIGN(blk
->size
, 4));
396 ret
= catpt_load_block(cdev
, chan
, paddr
+ offset
,
402 dev_err(cdev
->dev
, "restore block failed: %d\n", ret
);
406 offset
+= sizeof(*blk
) + blk
->size
;
412 static int catpt_load_module(struct catpt_dev
*cdev
,
413 struct dma_chan
*chan
, dma_addr_t paddr
,
414 struct catpt_fw_mod_hdr
*mod
)
416 struct catpt_module_type
*type
;
417 u32 offset
= sizeof(*mod
);
420 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
421 mod
, sizeof(*mod
), false);
423 type
= &cdev
->modules
[mod
->module_id
];
425 for (i
= 0; i
< mod
->blocks
; i
++) {
426 struct catpt_fw_block_hdr
*blk
;
429 blk
= (struct catpt_fw_block_hdr
*)((u8
*)mod
+ offset
);
431 ret
= catpt_load_block(cdev
, chan
, paddr
+ offset
, blk
, true);
433 dev_err(cdev
->dev
, "load block failed: %d\n", ret
);
438 * Save state window coordinates - these will be
439 * used to capture module state on D0 exit.
441 if (blk
->ram_type
== CATPT_RAM_TYPE_INSTANCE
) {
442 type
->state_offset
= blk
->ram_offset
;
443 type
->state_size
= blk
->size
;
446 offset
+= sizeof(*blk
) + blk
->size
;
449 /* init module type static info */
451 /* DSP expects address from module header substracted by 4 */
452 type
->entry_point
= mod
->entry_point
- 4;
453 type
->persistent_size
= mod
->persistent_size
;
454 type
->scratch_size
= mod
->scratch_size
;
459 static int catpt_restore_firmware(struct catpt_dev
*cdev
,
460 struct dma_chan
*chan
, dma_addr_t paddr
,
461 struct catpt_fw_hdr
*fw
)
463 u32 offset
= sizeof(*fw
);
466 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
467 fw
, sizeof(*fw
), false);
469 for (i
= 0; i
< fw
->modules
; i
++) {
470 struct catpt_fw_mod_hdr
*mod
;
473 mod
= (struct catpt_fw_mod_hdr
*)((u8
*)fw
+ offset
);
474 if (strncmp(fw
->signature
, mod
->signature
,
475 FW_SIGNATURE_SIZE
)) {
476 dev_err(cdev
->dev
, "module signature mismatch\n");
480 if (mod
->module_id
> CATPT_MODID_LAST
)
483 switch (mod
->module_id
) {
484 case CATPT_MODID_BASE_FW
:
485 ret
= catpt_restore_basefw(cdev
, chan
, paddr
+ offset
,
489 ret
= catpt_restore_module(cdev
, chan
, paddr
+ offset
,
495 dev_err(cdev
->dev
, "restore module failed: %d\n", ret
);
499 offset
+= sizeof(*mod
) + mod
->mod_size
;
505 static int catpt_load_firmware(struct catpt_dev
*cdev
,
506 struct dma_chan
*chan
, dma_addr_t paddr
,
507 struct catpt_fw_hdr
*fw
)
509 u32 offset
= sizeof(*fw
);
512 print_hex_dump_debug(__func__
, DUMP_PREFIX_OFFSET
, 8, 4,
513 fw
, sizeof(*fw
), false);
515 for (i
= 0; i
< fw
->modules
; i
++) {
516 struct catpt_fw_mod_hdr
*mod
;
519 mod
= (struct catpt_fw_mod_hdr
*)((u8
*)fw
+ offset
);
520 if (strncmp(fw
->signature
, mod
->signature
,
521 FW_SIGNATURE_SIZE
)) {
522 dev_err(cdev
->dev
, "module signature mismatch\n");
526 if (mod
->module_id
> CATPT_MODID_LAST
)
529 ret
= catpt_load_module(cdev
, chan
, paddr
+ offset
, mod
);
531 dev_err(cdev
->dev
, "load module failed: %d\n", ret
);
535 offset
+= sizeof(*mod
) + mod
->mod_size
;
541 static int catpt_load_image(struct catpt_dev
*cdev
, struct dma_chan
*chan
,
542 const char *name
, const char *signature
,
545 struct catpt_fw_hdr
*fw
;
546 struct firmware
*img
;
551 ret
= request_firmware((const struct firmware
**)&img
, name
, cdev
->dev
);
555 fw
= (struct catpt_fw_hdr
*)img
->data
;
556 if (strncmp(fw
->signature
, signature
, FW_SIGNATURE_SIZE
)) {
557 dev_err(cdev
->dev
, "firmware signature mismatch\n");
562 vaddr
= dma_alloc_coherent(cdev
->dev
, img
->size
, &paddr
, GFP_KERNEL
);
568 memcpy(vaddr
, img
->data
, img
->size
);
569 fw
= (struct catpt_fw_hdr
*)vaddr
;
571 ret
= catpt_restore_firmware(cdev
, chan
, paddr
, fw
);
573 ret
= catpt_load_firmware(cdev
, chan
, paddr
, fw
);
575 dma_free_coherent(cdev
->dev
, img
->size
, vaddr
, paddr
);
577 release_firmware(img
);
581 static int catpt_load_images(struct catpt_dev
*cdev
, bool restore
)
583 static const char *const names
[] = {
584 "intel/IntcSST1.bin",
585 "intel/IntcSST2.bin",
587 struct dma_chan
*chan
;
590 chan
= catpt_dma_request_config_chan(cdev
);
592 return PTR_ERR(chan
);
594 ret
= catpt_load_image(cdev
, chan
, names
[cdev
->spec
->core_id
- 1],
595 FW_SIGNATURE
, restore
);
597 goto release_dma_chan
;
600 goto release_dma_chan
;
601 ret
= catpt_restore_streams_context(cdev
, chan
);
603 dev_err(cdev
->dev
, "restore streams ctx failed: %d\n", ret
);
605 dma_release_channel(chan
);
609 int catpt_boot_firmware(struct catpt_dev
*cdev
, bool restore
)
613 catpt_dsp_stall(cdev
, true);
615 ret
= catpt_load_images(cdev
, restore
);
617 dev_err(cdev
->dev
, "load binaries failed: %d\n", ret
);
621 reinit_completion(&cdev
->fw_ready
);
622 catpt_dsp_stall(cdev
, false);
624 ret
= wait_for_completion_timeout(&cdev
->fw_ready
,
625 msecs_to_jiffies(FW_READY_TIMEOUT_MS
));
627 dev_err(cdev
->dev
, "firmware ready timeout\n");
631 /* update sram pg & clock once done booting */
632 catpt_dsp_update_srampge(cdev
, &cdev
->dram
, cdev
->spec
->dram_mask
);
633 catpt_dsp_update_srampge(cdev
, &cdev
->iram
, cdev
->spec
->iram_mask
);
635 return catpt_dsp_update_lpclock(cdev
);
638 int catpt_first_boot_firmware(struct catpt_dev
*cdev
)
640 struct resource
*res
;
643 ret
= catpt_boot_firmware(cdev
, false);
645 dev_err(cdev
->dev
, "basefw boot failed: %d\n", ret
);
649 /* restrict FW Core dump area */
650 __request_region(&cdev
->dram
, 0, 0x200, NULL
, 0);
651 /* restrict entire area following BASE_FW - highest offset in DRAM */
652 for (res
= cdev
->dram
.child
; res
->sibling
; res
= res
->sibling
)
654 __request_region(&cdev
->dram
, res
->end
+ 1,
655 cdev
->dram
.end
- res
->end
, NULL
, 0);
657 ret
= catpt_ipc_get_mixer_stream_info(cdev
, &cdev
->mixer
);
659 return CATPT_IPC_ERROR(ret
);
661 ret
= catpt_arm_stream_templates(cdev
);
663 dev_err(cdev
->dev
, "arm templates failed: %d\n", ret
);
667 /* update dram pg for scratch and restricted regions */
668 catpt_dsp_update_srampge(cdev
, &cdev
->dram
, cdev
->spec
->dram_mask
);