loader.c 15 KB

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