18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright 2019 NXP 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Author: Daniel Baluta <daniel.baluta@nxp.com> 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Hardware interface for audio DSP on i.MX8 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/firmware.h> 108c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 118c2ecf20Sopenharmony_ci#include <linux/of_address.h> 128c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 138c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <sound/sof.h> 178c2ecf20Sopenharmony_ci#include <sound/sof/xtensa.h> 188c2ecf20Sopenharmony_ci#include <linux/firmware/imx/ipc.h> 198c2ecf20Sopenharmony_ci#include <linux/firmware/imx/dsp.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/firmware/imx/svc/misc.h> 228c2ecf20Sopenharmony_ci#include <dt-bindings/firmware/imx/rsrc.h> 238c2ecf20Sopenharmony_ci#include "../ops.h" 248c2ecf20Sopenharmony_ci#include "imx-common.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* DSP memories */ 278c2ecf20Sopenharmony_ci#define IRAM_OFFSET 0x10000 288c2ecf20Sopenharmony_ci#define IRAM_SIZE (2 * 1024) 298c2ecf20Sopenharmony_ci#define DRAM0_OFFSET 0x0 308c2ecf20Sopenharmony_ci#define DRAM0_SIZE (32 * 1024) 318c2ecf20Sopenharmony_ci#define DRAM1_OFFSET 0x8000 328c2ecf20Sopenharmony_ci#define DRAM1_SIZE (32 * 1024) 338c2ecf20Sopenharmony_ci#define SYSRAM_OFFSET 0x18000 348c2ecf20Sopenharmony_ci#define SYSRAM_SIZE (256 * 1024) 358c2ecf20Sopenharmony_ci#define SYSROM_OFFSET 0x58000 368c2ecf20Sopenharmony_ci#define SYSROM_SIZE (192 * 1024) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define RESET_VECTOR_VADDR 0x596f8000 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define MBOX_OFFSET 0x800000 418c2ecf20Sopenharmony_ci#define MBOX_SIZE 0x1000 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct imx8_priv { 448c2ecf20Sopenharmony_ci struct device *dev; 458c2ecf20Sopenharmony_ci struct snd_sof_dev *sdev; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* DSP IPC handler */ 488c2ecf20Sopenharmony_ci struct imx_dsp_ipc *dsp_ipc; 498c2ecf20Sopenharmony_ci struct platform_device *ipc_dev; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* System Controller IPC handler */ 528c2ecf20Sopenharmony_ci struct imx_sc_ipc *sc_ipc; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Power domain handling */ 558c2ecf20Sopenharmony_ci int num_domains; 568c2ecf20Sopenharmony_ci struct device **pd_dev; 578c2ecf20Sopenharmony_ci struct device_link **link; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void imx8_get_reply(struct snd_sof_dev *sdev) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct snd_sof_ipc_msg *msg = sdev->msg; 648c2ecf20Sopenharmony_ci struct sof_ipc_reply reply; 658c2ecf20Sopenharmony_ci int ret = 0; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (!msg) { 688c2ecf20Sopenharmony_ci dev_warn(sdev->dev, "unexpected ipc interrupt\n"); 698c2ecf20Sopenharmony_ci return; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* get reply */ 738c2ecf20Sopenharmony_ci sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (reply.error < 0) { 768c2ecf20Sopenharmony_ci memcpy(msg->reply_data, &reply, sizeof(reply)); 778c2ecf20Sopenharmony_ci ret = reply.error; 788c2ecf20Sopenharmony_ci } else { 798c2ecf20Sopenharmony_ci /* reply has correct size? */ 808c2ecf20Sopenharmony_ci if (reply.hdr.size != msg->reply_size) { 818c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", 828c2ecf20Sopenharmony_ci msg->reply_size, reply.hdr.size); 838c2ecf20Sopenharmony_ci ret = -EINVAL; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* read the message */ 878c2ecf20Sopenharmony_ci if (msg->reply_size > 0) 888c2ecf20Sopenharmony_ci sof_mailbox_read(sdev, sdev->host_box.offset, 898c2ecf20Sopenharmony_ci msg->reply_data, msg->reply_size); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci msg->reply_error = ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci return MBOX_OFFSET; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return MBOX_OFFSET; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct imx8_priv *priv = imx_dsp_get_data(ipc); 1088c2ecf20Sopenharmony_ci unsigned long flags; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->sdev->ipc_lock, flags); 1118c2ecf20Sopenharmony_ci imx8_get_reply(priv->sdev); 1128c2ecf20Sopenharmony_ci snd_sof_ipc_reply(priv->sdev, 0); 1138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct imx8_priv *priv = imx_dsp_get_data(ipc); 1198c2ecf20Sopenharmony_ci u32 p; /* panic code */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Read the message from the debug box. */ 1228c2ecf20Sopenharmony_ci sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Check to see if the message is a panic code (0x0dead***) */ 1258c2ecf20Sopenharmony_ci if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) 1268c2ecf20Sopenharmony_ci snd_sof_dsp_panic(priv->sdev, p); 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci snd_sof_ipc_msgs_rx(priv->sdev); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct imx_dsp_ops dsp_ops = { 1328c2ecf20Sopenharmony_ci .handle_reply = imx8_dsp_handle_reply, 1338c2ecf20Sopenharmony_ci .handle_request = imx8_dsp_handle_request, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct imx8_priv *priv = sdev->pdata->hw_pdata; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 1418c2ecf20Sopenharmony_ci msg->msg_size); 1428c2ecf20Sopenharmony_ci imx_dsp_ring_doorbell(priv->dsp_ipc, 0); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* 1488c2ecf20Sopenharmony_ci * DSP control. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic int imx8x_run(struct snd_sof_dev *sdev) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; 1538c2ecf20Sopenharmony_ci int ret; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, 1568c2ecf20Sopenharmony_ci IMX_SC_C_OFS_SEL, 1); 1578c2ecf20Sopenharmony_ci if (ret < 0) { 1588c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Error system address offset source select\n"); 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, 1638c2ecf20Sopenharmony_ci IMX_SC_C_OFS_AUDIO, 0x80); 1648c2ecf20Sopenharmony_ci if (ret < 0) { 1658c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Error system address offset of AUDIO\n"); 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, 1708c2ecf20Sopenharmony_ci IMX_SC_C_OFS_PERIPH, 0x5A); 1718c2ecf20Sopenharmony_ci if (ret < 0) { 1728c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Error system address offset of PERIPH %d\n", 1738c2ecf20Sopenharmony_ci ret); 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, 1788c2ecf20Sopenharmony_ci IMX_SC_C_OFS_IRQ, 0x51); 1798c2ecf20Sopenharmony_ci if (ret < 0) { 1808c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Error system address offset of IRQ\n"); 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, 1858c2ecf20Sopenharmony_ci RESET_VECTOR_VADDR); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int imx8_run(struct snd_sof_dev *sdev) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, 1968c2ecf20Sopenharmony_ci IMX_SC_C_OFS_SEL, 0); 1978c2ecf20Sopenharmony_ci if (ret < 0) { 1988c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Error system address offset source select\n"); 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, 2038c2ecf20Sopenharmony_ci RESET_VECTOR_VADDR); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int imx8_probe(struct snd_sof_dev *sdev) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct platform_device *pdev = 2118c2ecf20Sopenharmony_ci container_of(sdev->dev, struct platform_device, dev); 2128c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 2138c2ecf20Sopenharmony_ci struct device_node *res_node; 2148c2ecf20Sopenharmony_ci struct resource *mmio; 2158c2ecf20Sopenharmony_ci struct imx8_priv *priv; 2168c2ecf20Sopenharmony_ci struct resource res; 2178c2ecf20Sopenharmony_ci u32 base, size; 2188c2ecf20Sopenharmony_ci int ret = 0; 2198c2ecf20Sopenharmony_ci int i; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 2228c2ecf20Sopenharmony_ci if (!priv) 2238c2ecf20Sopenharmony_ci return -ENOMEM; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci sdev->pdata->hw_pdata = priv; 2268c2ecf20Sopenharmony_ci priv->dev = sdev->dev; 2278c2ecf20Sopenharmony_ci priv->sdev = sdev; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* power up device associated power domains */ 2308c2ecf20Sopenharmony_ci priv->num_domains = of_count_phandle_with_args(np, "power-domains", 2318c2ecf20Sopenharmony_ci "#power-domain-cells"); 2328c2ecf20Sopenharmony_ci if (priv->num_domains < 0) { 2338c2ecf20Sopenharmony_ci dev_err(sdev->dev, "no power-domains property in %pOF\n", np); 2348c2ecf20Sopenharmony_ci return priv->num_domains; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains, 2388c2ecf20Sopenharmony_ci sizeof(*priv->pd_dev), GFP_KERNEL); 2398c2ecf20Sopenharmony_ci if (!priv->pd_dev) 2408c2ecf20Sopenharmony_ci return -ENOMEM; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains, 2438c2ecf20Sopenharmony_ci sizeof(*priv->link), GFP_KERNEL); 2448c2ecf20Sopenharmony_ci if (!priv->link) 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_domains; i++) { 2488c2ecf20Sopenharmony_ci priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i); 2498c2ecf20Sopenharmony_ci if (IS_ERR(priv->pd_dev[i])) { 2508c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->pd_dev[i]); 2518c2ecf20Sopenharmony_ci goto exit_unroll_pm; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i], 2548c2ecf20Sopenharmony_ci DL_FLAG_STATELESS | 2558c2ecf20Sopenharmony_ci DL_FLAG_PM_RUNTIME | 2568c2ecf20Sopenharmony_ci DL_FLAG_RPM_ACTIVE); 2578c2ecf20Sopenharmony_ci if (!priv->link[i]) { 2588c2ecf20Sopenharmony_ci ret = -ENOMEM; 2598c2ecf20Sopenharmony_ci dev_pm_domain_detach(priv->pd_dev[i], false); 2608c2ecf20Sopenharmony_ci goto exit_unroll_pm; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ret = imx_scu_get_handle(&priv->sc_ipc); 2658c2ecf20Sopenharmony_ci if (ret) { 2668c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n", 2678c2ecf20Sopenharmony_ci ret); 2688c2ecf20Sopenharmony_ci goto exit_unroll_pm; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", 2728c2ecf20Sopenharmony_ci PLATFORM_DEVID_NONE, 2738c2ecf20Sopenharmony_ci pdev, sizeof(*pdev)); 2748c2ecf20Sopenharmony_ci if (IS_ERR(priv->ipc_dev)) { 2758c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->ipc_dev); 2768c2ecf20Sopenharmony_ci goto exit_unroll_pm; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); 2808c2ecf20Sopenharmony_ci if (!priv->dsp_ipc) { 2818c2ecf20Sopenharmony_ci /* DSP IPC driver not probed yet, try later */ 2828c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 2838c2ecf20Sopenharmony_ci dev_err(sdev->dev, "Failed to get drvdata\n"); 2848c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci imx_dsp_set_data(priv->dsp_ipc, priv); 2888c2ecf20Sopenharmony_ci priv->dsp_ipc->ops = &dsp_ops; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* DSP base */ 2918c2ecf20Sopenharmony_ci mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2928c2ecf20Sopenharmony_ci if (mmio) { 2938c2ecf20Sopenharmony_ci base = mmio->start; 2948c2ecf20Sopenharmony_ci size = resource_size(mmio); 2958c2ecf20Sopenharmony_ci } else { 2968c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); 2978c2ecf20Sopenharmony_ci ret = -EINVAL; 2988c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); 3028c2ecf20Sopenharmony_ci if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { 3038c2ecf20Sopenharmony_ci dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", 3048c2ecf20Sopenharmony_ci base, size); 3058c2ecf20Sopenharmony_ci ret = -ENODEV; 3068c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci res_node = of_parse_phandle(np, "memory-region", 0); 3118c2ecf20Sopenharmony_ci if (!res_node) { 3128c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get memory region node\n"); 3138c2ecf20Sopenharmony_ci ret = -ENODEV; 3148c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ret = of_address_to_resource(res_node, 0, &res); 3188c2ecf20Sopenharmony_ci if (ret) { 3198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get reserved region address\n"); 3208c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, 3248c2ecf20Sopenharmony_ci resource_size(&res)); 3258c2ecf20Sopenharmony_ci if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { 3268c2ecf20Sopenharmony_ci dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", 3278c2ecf20Sopenharmony_ci base, size); 3288c2ecf20Sopenharmony_ci ret = -ENOMEM; 3298c2ecf20Sopenharmony_ci goto exit_pdev_unregister; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* set default mailbox offset for FW ready message */ 3348c2ecf20Sopenharmony_ci sdev->dsp_box.offset = MBOX_OFFSET; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ciexit_pdev_unregister: 3398c2ecf20Sopenharmony_ci platform_device_unregister(priv->ipc_dev); 3408c2ecf20Sopenharmony_ciexit_unroll_pm: 3418c2ecf20Sopenharmony_ci while (--i >= 0) { 3428c2ecf20Sopenharmony_ci device_link_del(priv->link[i]); 3438c2ecf20Sopenharmony_ci dev_pm_domain_detach(priv->pd_dev[i], false); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int imx8_remove(struct snd_sof_dev *sdev) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct imx8_priv *priv = sdev->pdata->hw_pdata; 3528c2ecf20Sopenharmony_ci int i; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci platform_device_unregister(priv->ipc_dev); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_domains; i++) { 3578c2ecf20Sopenharmony_ci device_link_del(priv->link[i]); 3588c2ecf20Sopenharmony_ci dev_pm_domain_detach(priv->pd_dev[i], false); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/* on i.MX8 there is 1 to 1 match between type and BAR idx */ 3658c2ecf20Sopenharmony_cistatic int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci return type; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void imx8_ipc_msg_data(struct snd_sof_dev *sdev, 3718c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 3728c2ecf20Sopenharmony_ci void *p, size_t sz) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, 3788c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 3798c2ecf20Sopenharmony_ci const struct sof_ipc_pcm_params_reply *reply) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver imx8_dai[] = { 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci .name = "esai0", 3878c2ecf20Sopenharmony_ci .playback = { 3888c2ecf20Sopenharmony_ci .channels_min = 1, 3898c2ecf20Sopenharmony_ci .channels_max = 8, 3908c2ecf20Sopenharmony_ci }, 3918c2ecf20Sopenharmony_ci .capture = { 3928c2ecf20Sopenharmony_ci .channels_min = 1, 3938c2ecf20Sopenharmony_ci .channels_max = 8, 3948c2ecf20Sopenharmony_ci }, 3958c2ecf20Sopenharmony_ci}, 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci .name = "sai1", 3988c2ecf20Sopenharmony_ci .playback = { 3998c2ecf20Sopenharmony_ci .channels_min = 1, 4008c2ecf20Sopenharmony_ci .channels_max = 32, 4018c2ecf20Sopenharmony_ci }, 4028c2ecf20Sopenharmony_ci .capture = { 4038c2ecf20Sopenharmony_ci .channels_min = 1, 4048c2ecf20Sopenharmony_ci .channels_max = 32, 4058c2ecf20Sopenharmony_ci }, 4068c2ecf20Sopenharmony_ci}, 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* i.MX8 ops */ 4108c2ecf20Sopenharmony_cistruct snd_sof_dsp_ops sof_imx8_ops = { 4118c2ecf20Sopenharmony_ci /* probe and remove */ 4128c2ecf20Sopenharmony_ci .probe = imx8_probe, 4138c2ecf20Sopenharmony_ci .remove = imx8_remove, 4148c2ecf20Sopenharmony_ci /* DSP core boot */ 4158c2ecf20Sopenharmony_ci .run = imx8_run, 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Block IO */ 4188c2ecf20Sopenharmony_ci .block_read = sof_block_read, 4198c2ecf20Sopenharmony_ci .block_write = sof_block_write, 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Module IO */ 4228c2ecf20Sopenharmony_ci .read64 = sof_io_read64, 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* ipc */ 4258c2ecf20Sopenharmony_ci .send_msg = imx8_send_msg, 4268c2ecf20Sopenharmony_ci .fw_ready = sof_fw_ready, 4278c2ecf20Sopenharmony_ci .get_mailbox_offset = imx8_get_mailbox_offset, 4288c2ecf20Sopenharmony_ci .get_window_offset = imx8_get_window_offset, 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci .ipc_msg_data = imx8_ipc_msg_data, 4318c2ecf20Sopenharmony_ci .ipc_pcm_params = imx8_ipc_pcm_params, 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* module loading */ 4348c2ecf20Sopenharmony_ci .load_module = snd_sof_parse_module_memcpy, 4358c2ecf20Sopenharmony_ci .get_bar_index = imx8_get_bar_index, 4368c2ecf20Sopenharmony_ci /* firmware loading */ 4378c2ecf20Sopenharmony_ci .load_firmware = snd_sof_load_firmware_memcpy, 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* Debug information */ 4408c2ecf20Sopenharmony_ci .dbg_dump = imx8_dump, 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* Firmware ops */ 4438c2ecf20Sopenharmony_ci .arch_ops = &sof_xtensa_arch_ops, 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* DAI drivers */ 4468c2ecf20Sopenharmony_ci .drv = imx8_dai, 4478c2ecf20Sopenharmony_ci .num_drv = ARRAY_SIZE(imx8_dai), 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* ALSA HW info flags */ 4508c2ecf20Sopenharmony_ci .hw_info = SNDRV_PCM_INFO_MMAP | 4518c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 4528c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 4538c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 4548c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sof_imx8_ops); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* i.MX8X ops */ 4598c2ecf20Sopenharmony_cistruct snd_sof_dsp_ops sof_imx8x_ops = { 4608c2ecf20Sopenharmony_ci /* probe and remove */ 4618c2ecf20Sopenharmony_ci .probe = imx8_probe, 4628c2ecf20Sopenharmony_ci .remove = imx8_remove, 4638c2ecf20Sopenharmony_ci /* DSP core boot */ 4648c2ecf20Sopenharmony_ci .run = imx8x_run, 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Block IO */ 4678c2ecf20Sopenharmony_ci .block_read = sof_block_read, 4688c2ecf20Sopenharmony_ci .block_write = sof_block_write, 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Module IO */ 4718c2ecf20Sopenharmony_ci .read64 = sof_io_read64, 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* ipc */ 4748c2ecf20Sopenharmony_ci .send_msg = imx8_send_msg, 4758c2ecf20Sopenharmony_ci .fw_ready = sof_fw_ready, 4768c2ecf20Sopenharmony_ci .get_mailbox_offset = imx8_get_mailbox_offset, 4778c2ecf20Sopenharmony_ci .get_window_offset = imx8_get_window_offset, 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci .ipc_msg_data = imx8_ipc_msg_data, 4808c2ecf20Sopenharmony_ci .ipc_pcm_params = imx8_ipc_pcm_params, 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* module loading */ 4838c2ecf20Sopenharmony_ci .load_module = snd_sof_parse_module_memcpy, 4848c2ecf20Sopenharmony_ci .get_bar_index = imx8_get_bar_index, 4858c2ecf20Sopenharmony_ci /* firmware loading */ 4868c2ecf20Sopenharmony_ci .load_firmware = snd_sof_load_firmware_memcpy, 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* Debug information */ 4898c2ecf20Sopenharmony_ci .dbg_dump = imx8_dump, 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Firmware ops */ 4928c2ecf20Sopenharmony_ci .arch_ops = &sof_xtensa_arch_ops, 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* DAI drivers */ 4958c2ecf20Sopenharmony_ci .drv = imx8_dai, 4968c2ecf20Sopenharmony_ci .num_drv = ARRAY_SIZE(imx8_dai), 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* ALSA HW info flags */ 4998c2ecf20Sopenharmony_ci .hw_info = SNDRV_PCM_INFO_MMAP | 5008c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 5018c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 5028c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 5038c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sof_imx8x_ops); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); 5088c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 509