imx8.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  2. //
  3. // Copyright 2019 NXP
  4. //
  5. // Author: Daniel Baluta <daniel.baluta@nxp.com>
  6. //
  7. // Hardware interface for audio DSP on i.MX8
  8. #include <linux/firmware.h>
  9. #include <linux/of_platform.h>
  10. #include <linux/of_address.h>
  11. #include <linux/of_irq.h>
  12. #include <linux/pm_domain.h>
  13. #include <linux/module.h>
  14. #include <sound/sof.h>
  15. #include <sound/sof/xtensa.h>
  16. #include <linux/firmware/imx/ipc.h>
  17. #include <linux/firmware/imx/dsp.h>
  18. #include <linux/firmware/imx/svc/misc.h>
  19. #include <dt-bindings/firmware/imx/rsrc.h>
  20. #include "../ops.h"
  21. #include "../sof-of-dev.h"
  22. #include "imx-common.h"
  23. /* DSP memories */
  24. #define IRAM_OFFSET 0x10000
  25. #define IRAM_SIZE (2 * 1024)
  26. #define DRAM0_OFFSET 0x0
  27. #define DRAM0_SIZE (32 * 1024)
  28. #define DRAM1_OFFSET 0x8000
  29. #define DRAM1_SIZE (32 * 1024)
  30. #define SYSRAM_OFFSET 0x18000
  31. #define SYSRAM_SIZE (256 * 1024)
  32. #define SYSROM_OFFSET 0x58000
  33. #define SYSROM_SIZE (192 * 1024)
  34. #define RESET_VECTOR_VADDR 0x596f8000
  35. #define MBOX_OFFSET 0x800000
  36. #define MBOX_SIZE 0x1000
  37. struct imx8_priv {
  38. struct device *dev;
  39. struct snd_sof_dev *sdev;
  40. /* DSP IPC handler */
  41. struct imx_dsp_ipc *dsp_ipc;
  42. struct platform_device *ipc_dev;
  43. /* System Controller IPC handler */
  44. struct imx_sc_ipc *sc_ipc;
  45. /* Power domain handling */
  46. int num_domains;
  47. struct device **pd_dev;
  48. struct device_link **link;
  49. struct clk_bulk_data *clks;
  50. int clk_num;
  51. };
  52. static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev)
  53. {
  54. return MBOX_OFFSET;
  55. }
  56. static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id)
  57. {
  58. return MBOX_OFFSET;
  59. }
  60. static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc)
  61. {
  62. struct imx8_priv *priv = imx_dsp_get_data(ipc);
  63. unsigned long flags;
  64. spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
  65. snd_sof_ipc_process_reply(priv->sdev, 0);
  66. spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
  67. }
  68. static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc)
  69. {
  70. struct imx8_priv *priv = imx_dsp_get_data(ipc);
  71. u32 p; /* panic code */
  72. /* Read the message from the debug box. */
  73. sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
  74. /* Check to see if the message is a panic code (0x0dead***) */
  75. if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
  76. snd_sof_dsp_panic(priv->sdev, p, true);
  77. else
  78. snd_sof_ipc_msgs_rx(priv->sdev);
  79. }
  80. static struct imx_dsp_ops dsp_ops = {
  81. .handle_reply = imx8_dsp_handle_reply,
  82. .handle_request = imx8_dsp_handle_request,
  83. };
  84. static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
  85. {
  86. struct imx8_priv *priv = sdev->pdata->hw_pdata;
  87. sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
  88. msg->msg_size);
  89. imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
  90. return 0;
  91. }
  92. /*
  93. * DSP control.
  94. */
  95. static int imx8x_run(struct snd_sof_dev *sdev)
  96. {
  97. struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
  98. int ret;
  99. ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
  100. IMX_SC_C_OFS_SEL, 1);
  101. if (ret < 0) {
  102. dev_err(sdev->dev, "Error system address offset source select\n");
  103. return ret;
  104. }
  105. ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
  106. IMX_SC_C_OFS_AUDIO, 0x80);
  107. if (ret < 0) {
  108. dev_err(sdev->dev, "Error system address offset of AUDIO\n");
  109. return ret;
  110. }
  111. ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
  112. IMX_SC_C_OFS_PERIPH, 0x5A);
  113. if (ret < 0) {
  114. dev_err(sdev->dev, "Error system address offset of PERIPH %d\n",
  115. ret);
  116. return ret;
  117. }
  118. ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
  119. IMX_SC_C_OFS_IRQ, 0x51);
  120. if (ret < 0) {
  121. dev_err(sdev->dev, "Error system address offset of IRQ\n");
  122. return ret;
  123. }
  124. imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
  125. RESET_VECTOR_VADDR);
  126. return 0;
  127. }
  128. static int imx8_run(struct snd_sof_dev *sdev)
  129. {
  130. struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
  131. int ret;
  132. ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
  133. IMX_SC_C_OFS_SEL, 0);
  134. if (ret < 0) {
  135. dev_err(sdev->dev, "Error system address offset source select\n");
  136. return ret;
  137. }
  138. imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
  139. RESET_VECTOR_VADDR);
  140. return 0;
  141. }
  142. static int imx8_probe(struct snd_sof_dev *sdev)
  143. {
  144. struct platform_device *pdev =
  145. container_of(sdev->dev, struct platform_device, dev);
  146. struct device_node *np = pdev->dev.of_node;
  147. struct device_node *res_node;
  148. struct resource *mmio;
  149. struct imx8_priv *priv;
  150. struct resource res;
  151. u32 base, size;
  152. int ret = 0;
  153. int i;
  154. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  155. if (!priv)
  156. return -ENOMEM;
  157. sdev->num_cores = 1;
  158. sdev->pdata->hw_pdata = priv;
  159. priv->dev = sdev->dev;
  160. priv->sdev = sdev;
  161. /* power up device associated power domains */
  162. priv->num_domains = of_count_phandle_with_args(np, "power-domains",
  163. "#power-domain-cells");
  164. if (priv->num_domains < 0) {
  165. dev_err(sdev->dev, "no power-domains property in %pOF\n", np);
  166. return priv->num_domains;
  167. }
  168. priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
  169. sizeof(*priv->pd_dev), GFP_KERNEL);
  170. if (!priv->pd_dev)
  171. return -ENOMEM;
  172. priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
  173. sizeof(*priv->link), GFP_KERNEL);
  174. if (!priv->link)
  175. return -ENOMEM;
  176. for (i = 0; i < priv->num_domains; i++) {
  177. priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i);
  178. if (IS_ERR(priv->pd_dev[i])) {
  179. ret = PTR_ERR(priv->pd_dev[i]);
  180. goto exit_unroll_pm;
  181. }
  182. priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i],
  183. DL_FLAG_STATELESS |
  184. DL_FLAG_PM_RUNTIME |
  185. DL_FLAG_RPM_ACTIVE);
  186. if (!priv->link[i]) {
  187. ret = -ENOMEM;
  188. dev_pm_domain_detach(priv->pd_dev[i], false);
  189. goto exit_unroll_pm;
  190. }
  191. }
  192. ret = imx_scu_get_handle(&priv->sc_ipc);
  193. if (ret) {
  194. dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n",
  195. ret);
  196. goto exit_unroll_pm;
  197. }
  198. priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
  199. PLATFORM_DEVID_NONE,
  200. pdev, sizeof(*pdev));
  201. if (IS_ERR(priv->ipc_dev)) {
  202. ret = PTR_ERR(priv->ipc_dev);
  203. goto exit_unroll_pm;
  204. }
  205. priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
  206. if (!priv->dsp_ipc) {
  207. /* DSP IPC driver not probed yet, try later */
  208. ret = -EPROBE_DEFER;
  209. dev_err(sdev->dev, "Failed to get drvdata\n");
  210. goto exit_pdev_unregister;
  211. }
  212. imx_dsp_set_data(priv->dsp_ipc, priv);
  213. priv->dsp_ipc->ops = &dsp_ops;
  214. /* DSP base */
  215. mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  216. if (mmio) {
  217. base = mmio->start;
  218. size = resource_size(mmio);
  219. } else {
  220. dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
  221. ret = -EINVAL;
  222. goto exit_pdev_unregister;
  223. }
  224. sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
  225. if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
  226. dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
  227. base, size);
  228. ret = -ENODEV;
  229. goto exit_pdev_unregister;
  230. }
  231. sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
  232. res_node = of_parse_phandle(np, "memory-region", 0);
  233. if (!res_node) {
  234. dev_err(&pdev->dev, "failed to get memory region node\n");
  235. ret = -ENODEV;
  236. goto exit_pdev_unregister;
  237. }
  238. ret = of_address_to_resource(res_node, 0, &res);
  239. of_node_put(res_node);
  240. if (ret) {
  241. dev_err(&pdev->dev, "failed to get reserved region address\n");
  242. goto exit_pdev_unregister;
  243. }
  244. sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
  245. resource_size(&res));
  246. if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
  247. dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
  248. base, size);
  249. ret = -ENOMEM;
  250. goto exit_pdev_unregister;
  251. }
  252. sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
  253. /* set default mailbox offset for FW ready message */
  254. sdev->dsp_box.offset = MBOX_OFFSET;
  255. ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
  256. if (ret < 0) {
  257. dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
  258. goto exit_pdev_unregister;
  259. }
  260. priv->clk_num = ret;
  261. ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
  262. if (ret < 0) {
  263. dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
  264. goto exit_pdev_unregister;
  265. }
  266. return 0;
  267. exit_pdev_unregister:
  268. platform_device_unregister(priv->ipc_dev);
  269. exit_unroll_pm:
  270. while (--i >= 0) {
  271. device_link_del(priv->link[i]);
  272. dev_pm_domain_detach(priv->pd_dev[i], false);
  273. }
  274. return ret;
  275. }
  276. static void imx8_remove(struct snd_sof_dev *sdev)
  277. {
  278. struct imx8_priv *priv = sdev->pdata->hw_pdata;
  279. int i;
  280. clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
  281. platform_device_unregister(priv->ipc_dev);
  282. for (i = 0; i < priv->num_domains; i++) {
  283. device_link_del(priv->link[i]);
  284. dev_pm_domain_detach(priv->pd_dev[i], false);
  285. }
  286. }
  287. /* on i.MX8 there is 1 to 1 match between type and BAR idx */
  288. static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type)
  289. {
  290. /* Only IRAM and SRAM bars are valid */
  291. switch (type) {
  292. case SOF_FW_BLK_TYPE_IRAM:
  293. case SOF_FW_BLK_TYPE_SRAM:
  294. return type;
  295. default:
  296. return -EINVAL;
  297. }
  298. }
  299. static void imx8_suspend(struct snd_sof_dev *sdev)
  300. {
  301. int i;
  302. struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
  303. for (i = 0; i < DSP_MU_CHAN_NUM; i++)
  304. imx_dsp_free_channel(priv->dsp_ipc, i);
  305. clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
  306. }
  307. static int imx8_resume(struct snd_sof_dev *sdev)
  308. {
  309. struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
  310. int ret;
  311. int i;
  312. ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
  313. if (ret < 0) {
  314. dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
  315. return ret;
  316. }
  317. for (i = 0; i < DSP_MU_CHAN_NUM; i++)
  318. imx_dsp_request_channel(priv->dsp_ipc, i);
  319. return 0;
  320. }
  321. static int imx8_dsp_runtime_resume(struct snd_sof_dev *sdev)
  322. {
  323. int ret;
  324. const struct sof_dsp_power_state target_dsp_state = {
  325. .state = SOF_DSP_PM_D0,
  326. };
  327. ret = imx8_resume(sdev);
  328. if (ret < 0)
  329. return ret;
  330. return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
  331. }
  332. static int imx8_dsp_runtime_suspend(struct snd_sof_dev *sdev)
  333. {
  334. const struct sof_dsp_power_state target_dsp_state = {
  335. .state = SOF_DSP_PM_D3,
  336. };
  337. imx8_suspend(sdev);
  338. return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
  339. }
  340. static int imx8_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
  341. {
  342. const struct sof_dsp_power_state target_dsp_state = {
  343. .state = target_state,
  344. };
  345. if (!pm_runtime_suspended(sdev->dev))
  346. imx8_suspend(sdev);
  347. return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
  348. }
  349. static int imx8_dsp_resume(struct snd_sof_dev *sdev)
  350. {
  351. int ret;
  352. const struct sof_dsp_power_state target_dsp_state = {
  353. .state = SOF_DSP_PM_D0,
  354. };
  355. ret = imx8_resume(sdev);
  356. if (ret < 0)
  357. return ret;
  358. if (pm_runtime_suspended(sdev->dev)) {
  359. pm_runtime_disable(sdev->dev);
  360. pm_runtime_set_active(sdev->dev);
  361. pm_runtime_mark_last_busy(sdev->dev);
  362. pm_runtime_enable(sdev->dev);
  363. pm_runtime_idle(sdev->dev);
  364. }
  365. return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
  366. }
  367. static struct snd_soc_dai_driver imx8_dai[] = {
  368. {
  369. .name = "esai0",
  370. .playback = {
  371. .channels_min = 1,
  372. .channels_max = 8,
  373. },
  374. .capture = {
  375. .channels_min = 1,
  376. .channels_max = 8,
  377. },
  378. },
  379. {
  380. .name = "sai1",
  381. .playback = {
  382. .channels_min = 1,
  383. .channels_max = 32,
  384. },
  385. .capture = {
  386. .channels_min = 1,
  387. .channels_max = 32,
  388. },
  389. },
  390. };
  391. static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev,
  392. const struct sof_dsp_power_state *target_state)
  393. {
  394. sdev->dsp_power_state = *target_state;
  395. return 0;
  396. }
  397. /* i.MX8 ops */
  398. static const struct snd_sof_dsp_ops sof_imx8_ops = {
  399. /* probe and remove */
  400. .probe = imx8_probe,
  401. .remove = imx8_remove,
  402. /* DSP core boot */
  403. .run = imx8_run,
  404. /* Block IO */
  405. .block_read = sof_block_read,
  406. .block_write = sof_block_write,
  407. /* Mailbox IO */
  408. .mailbox_read = sof_mailbox_read,
  409. .mailbox_write = sof_mailbox_write,
  410. /* ipc */
  411. .send_msg = imx8_send_msg,
  412. .get_mailbox_offset = imx8_get_mailbox_offset,
  413. .get_window_offset = imx8_get_window_offset,
  414. .ipc_msg_data = sof_ipc_msg_data,
  415. .set_stream_data_offset = sof_set_stream_data_offset,
  416. .get_bar_index = imx8_get_bar_index,
  417. /* firmware loading */
  418. .load_firmware = snd_sof_load_firmware_memcpy,
  419. /* Debug information */
  420. .dbg_dump = imx8_dump,
  421. .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
  422. /* stream callbacks */
  423. .pcm_open = sof_stream_pcm_open,
  424. .pcm_close = sof_stream_pcm_close,
  425. /* Firmware ops */
  426. .dsp_arch_ops = &sof_xtensa_arch_ops,
  427. /* DAI drivers */
  428. .drv = imx8_dai,
  429. .num_drv = ARRAY_SIZE(imx8_dai),
  430. /* ALSA HW info flags */
  431. .hw_info = SNDRV_PCM_INFO_MMAP |
  432. SNDRV_PCM_INFO_MMAP_VALID |
  433. SNDRV_PCM_INFO_INTERLEAVED |
  434. SNDRV_PCM_INFO_PAUSE |
  435. SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
  436. /* PM */
  437. .runtime_suspend = imx8_dsp_runtime_suspend,
  438. .runtime_resume = imx8_dsp_runtime_resume,
  439. .suspend = imx8_dsp_suspend,
  440. .resume = imx8_dsp_resume,
  441. .set_power_state = imx8_dsp_set_power_state,
  442. };
  443. /* i.MX8X ops */
  444. static const struct snd_sof_dsp_ops sof_imx8x_ops = {
  445. /* probe and remove */
  446. .probe = imx8_probe,
  447. .remove = imx8_remove,
  448. /* DSP core boot */
  449. .run = imx8x_run,
  450. /* Block IO */
  451. .block_read = sof_block_read,
  452. .block_write = sof_block_write,
  453. /* Mailbox IO */
  454. .mailbox_read = sof_mailbox_read,
  455. .mailbox_write = sof_mailbox_write,
  456. /* ipc */
  457. .send_msg = imx8_send_msg,
  458. .get_mailbox_offset = imx8_get_mailbox_offset,
  459. .get_window_offset = imx8_get_window_offset,
  460. .ipc_msg_data = sof_ipc_msg_data,
  461. .set_stream_data_offset = sof_set_stream_data_offset,
  462. .get_bar_index = imx8_get_bar_index,
  463. /* firmware loading */
  464. .load_firmware = snd_sof_load_firmware_memcpy,
  465. /* Debug information */
  466. .dbg_dump = imx8_dump,
  467. .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
  468. /* stream callbacks */
  469. .pcm_open = sof_stream_pcm_open,
  470. .pcm_close = sof_stream_pcm_close,
  471. /* Firmware ops */
  472. .dsp_arch_ops = &sof_xtensa_arch_ops,
  473. /* DAI drivers */
  474. .drv = imx8_dai,
  475. .num_drv = ARRAY_SIZE(imx8_dai),
  476. /* PM */
  477. .runtime_suspend = imx8_dsp_runtime_suspend,
  478. .runtime_resume = imx8_dsp_runtime_resume,
  479. .suspend = imx8_dsp_suspend,
  480. .resume = imx8_dsp_resume,
  481. .set_power_state = imx8_dsp_set_power_state,
  482. /* ALSA HW info flags */
  483. .hw_info = SNDRV_PCM_INFO_MMAP |
  484. SNDRV_PCM_INFO_MMAP_VALID |
  485. SNDRV_PCM_INFO_INTERLEAVED |
  486. SNDRV_PCM_INFO_PAUSE |
  487. SNDRV_PCM_INFO_BATCH |
  488. SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
  489. };
  490. static struct snd_sof_of_mach sof_imx8_machs[] = {
  491. {
  492. .compatible = "fsl,imx8qxp-mek",
  493. .sof_tplg_filename = "sof-imx8-wm8960.tplg",
  494. .drv_name = "asoc-audio-graph-card2",
  495. },
  496. {
  497. .compatible = "fsl,imx8qm-mek",
  498. .sof_tplg_filename = "sof-imx8-wm8960.tplg",
  499. .drv_name = "asoc-audio-graph-card2",
  500. },
  501. {}
  502. };
  503. static struct sof_dev_desc sof_of_imx8qxp_desc = {
  504. .of_machines = sof_imx8_machs,
  505. .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
  506. .ipc_default = SOF_IPC_TYPE_3,
  507. .default_fw_path = {
  508. [SOF_IPC_TYPE_3] = "imx/sof",
  509. },
  510. .default_tplg_path = {
  511. [SOF_IPC_TYPE_3] = "imx/sof-tplg",
  512. },
  513. .default_fw_filename = {
  514. [SOF_IPC_TYPE_3] = "sof-imx8x.ri",
  515. },
  516. .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
  517. .ops = &sof_imx8x_ops,
  518. };
  519. static struct sof_dev_desc sof_of_imx8qm_desc = {
  520. .of_machines = sof_imx8_machs,
  521. .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
  522. .ipc_default = SOF_IPC_TYPE_3,
  523. .default_fw_path = {
  524. [SOF_IPC_TYPE_3] = "imx/sof",
  525. },
  526. .default_tplg_path = {
  527. [SOF_IPC_TYPE_3] = "imx/sof-tplg",
  528. },
  529. .default_fw_filename = {
  530. [SOF_IPC_TYPE_3] = "sof-imx8.ri",
  531. },
  532. .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
  533. .ops = &sof_imx8_ops,
  534. };
  535. static const struct of_device_id sof_of_imx8_ids[] = {
  536. { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
  537. { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
  538. { }
  539. };
  540. MODULE_DEVICE_TABLE(of, sof_of_imx8_ids);
  541. /* DT driver definition */
  542. static struct platform_driver snd_sof_of_imx8_driver = {
  543. .probe = sof_of_probe,
  544. .remove = sof_of_remove,
  545. .driver = {
  546. .name = "sof-audio-of-imx8",
  547. .pm = &sof_of_pm,
  548. .of_match_table = sof_of_imx8_ids,
  549. },
  550. };
  551. module_platform_driver(snd_sof_of_imx8_driver);
  552. MODULE_LICENSE("Dual BSD/GPL");
  553. MODULE_DESCRIPTION("SOF support for IMX8 platforms");
  554. MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);