11f0214a8STinghan Shen // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 21f0214a8STinghan Shen // 31f0214a8STinghan Shen // Copyright(c) 2022 Mediatek Inc. All rights reserved. 41f0214a8STinghan Shen // 51f0214a8STinghan Shen // Author: Allen-KH Cheng <allen-kh.cheng@mediatek.com> 61f0214a8STinghan Shen // Tinghan Shen <tinghan.shen@mediatek.com> 71f0214a8STinghan Shen 81f0214a8STinghan Shen /* 91f0214a8STinghan Shen * Hardware interface for audio DSP on mt8186 101f0214a8STinghan Shen */ 111f0214a8STinghan Shen 121f0214a8STinghan Shen #include <linux/delay.h> 131f0214a8STinghan Shen #include <linux/firmware.h> 141f0214a8STinghan Shen #include <linux/io.h> 151f0214a8STinghan Shen #include <linux/of_address.h> 161f0214a8STinghan Shen #include <linux/of_irq.h> 171f0214a8STinghan Shen #include <linux/of_platform.h> 181f0214a8STinghan Shen #include <linux/of_reserved_mem.h> 191f0214a8STinghan Shen #include <linux/module.h> 201f0214a8STinghan Shen 211f0214a8STinghan Shen #include <sound/sof.h> 221f0214a8STinghan Shen #include <sound/sof/xtensa.h> 231f0214a8STinghan Shen #include "../../ops.h" 241f0214a8STinghan Shen #include "../../sof-of-dev.h" 251f0214a8STinghan Shen #include "../../sof-audio.h" 261f0214a8STinghan Shen #include "../adsp_helper.h" 271f0214a8STinghan Shen #include "mt8186.h" 28210b3ab9STinghan Shen #include "mt8186-clk.h" 291f0214a8STinghan Shen 30e0100bfdSTinghan Shen static int mt8186_get_mailbox_offset(struct snd_sof_dev *sdev) 31e0100bfdSTinghan Shen { 32e0100bfdSTinghan Shen return MBOX_OFFSET; 33e0100bfdSTinghan Shen } 34e0100bfdSTinghan Shen 35e0100bfdSTinghan Shen static int mt8186_get_window_offset(struct snd_sof_dev *sdev, u32 id) 36e0100bfdSTinghan Shen { 37e0100bfdSTinghan Shen return MBOX_OFFSET; 38e0100bfdSTinghan Shen } 39e0100bfdSTinghan Shen 40e0100bfdSTinghan Shen static int mt8186_send_msg(struct snd_sof_dev *sdev, 41e0100bfdSTinghan Shen struct snd_sof_ipc_msg *msg) 42e0100bfdSTinghan Shen { 43e0100bfdSTinghan Shen struct adsp_priv *priv = sdev->pdata->hw_pdata; 44e0100bfdSTinghan Shen 45e0100bfdSTinghan Shen sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 46e0100bfdSTinghan Shen msg->msg_size); 47e0100bfdSTinghan Shen 48e0100bfdSTinghan Shen return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); 49e0100bfdSTinghan Shen } 50e0100bfdSTinghan Shen 51e0100bfdSTinghan Shen static void mt8186_get_reply(struct snd_sof_dev *sdev) 52e0100bfdSTinghan Shen { 53e0100bfdSTinghan Shen struct snd_sof_ipc_msg *msg = sdev->msg; 54e0100bfdSTinghan Shen struct sof_ipc_reply reply; 55e0100bfdSTinghan Shen int ret = 0; 56e0100bfdSTinghan Shen 57e0100bfdSTinghan Shen if (!msg) { 58e0100bfdSTinghan Shen dev_warn(sdev->dev, "unexpected ipc interrupt\n"); 59e0100bfdSTinghan Shen return; 60e0100bfdSTinghan Shen } 61e0100bfdSTinghan Shen 62e0100bfdSTinghan Shen /* get reply */ 63e0100bfdSTinghan Shen sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); 64e0100bfdSTinghan Shen if (reply.error < 0) { 65e0100bfdSTinghan Shen memcpy(msg->reply_data, &reply, sizeof(reply)); 66e0100bfdSTinghan Shen ret = reply.error; 67e0100bfdSTinghan Shen } else { 68e0100bfdSTinghan Shen /* reply has correct size? */ 69e0100bfdSTinghan Shen if (reply.hdr.size != msg->reply_size) { 70e0100bfdSTinghan Shen dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", 71e0100bfdSTinghan Shen msg->reply_size, reply.hdr.size); 72e0100bfdSTinghan Shen ret = -EINVAL; 73e0100bfdSTinghan Shen } 74e0100bfdSTinghan Shen 75e0100bfdSTinghan Shen /* read the message */ 76e0100bfdSTinghan Shen if (msg->reply_size > 0) 77e0100bfdSTinghan Shen sof_mailbox_read(sdev, sdev->host_box.offset, 78e0100bfdSTinghan Shen msg->reply_data, msg->reply_size); 79e0100bfdSTinghan Shen } 80e0100bfdSTinghan Shen 81e0100bfdSTinghan Shen msg->reply_error = ret; 82e0100bfdSTinghan Shen } 83e0100bfdSTinghan Shen 84e0100bfdSTinghan Shen static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc) 85e0100bfdSTinghan Shen { 86e0100bfdSTinghan Shen struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); 87e0100bfdSTinghan Shen unsigned long flags; 88e0100bfdSTinghan Shen 89e0100bfdSTinghan Shen spin_lock_irqsave(&priv->sdev->ipc_lock, flags); 90e0100bfdSTinghan Shen mt8186_get_reply(priv->sdev); 91e0100bfdSTinghan Shen snd_sof_ipc_reply(priv->sdev, 0); 92e0100bfdSTinghan Shen spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); 93e0100bfdSTinghan Shen } 94e0100bfdSTinghan Shen 95e0100bfdSTinghan Shen static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc) 96e0100bfdSTinghan Shen { 97e0100bfdSTinghan Shen struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); 98e0100bfdSTinghan Shen u32 p; /* panic code */ 99e0100bfdSTinghan Shen int ret; 100e0100bfdSTinghan Shen 101e0100bfdSTinghan Shen /* Read the message from the debug box. */ 102e0100bfdSTinghan Shen sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, 103e0100bfdSTinghan Shen &p, sizeof(p)); 104e0100bfdSTinghan Shen 105e0100bfdSTinghan Shen /* Check to see if the message is a panic code 0x0dead*** */ 106e0100bfdSTinghan Shen if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { 107e0100bfdSTinghan Shen snd_sof_dsp_panic(priv->sdev, p, true); 108e0100bfdSTinghan Shen } else { 109e0100bfdSTinghan Shen snd_sof_ipc_msgs_rx(priv->sdev); 110e0100bfdSTinghan Shen 111e0100bfdSTinghan Shen /* tell DSP cmd is done */ 112e0100bfdSTinghan Shen ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP); 113e0100bfdSTinghan Shen if (ret) 114e0100bfdSTinghan Shen dev_err(priv->dev, "request send ipc failed"); 115e0100bfdSTinghan Shen } 116e0100bfdSTinghan Shen } 117e0100bfdSTinghan Shen 118e0100bfdSTinghan Shen static struct mtk_adsp_ipc_ops dsp_ops = { 119e0100bfdSTinghan Shen .handle_reply = mt8186_dsp_handle_reply, 120e0100bfdSTinghan Shen .handle_request = mt8186_dsp_handle_request, 121e0100bfdSTinghan Shen }; 122e0100bfdSTinghan Shen 1231f0214a8STinghan Shen static int platform_parse_resource(struct platform_device *pdev, void *data) 1241f0214a8STinghan Shen { 1251f0214a8STinghan Shen struct resource *mmio; 1261f0214a8STinghan Shen struct resource res; 1271f0214a8STinghan Shen struct device_node *mem_region; 1281f0214a8STinghan Shen struct device *dev = &pdev->dev; 1291f0214a8STinghan Shen struct mtk_adsp_chip_info *adsp = data; 1301f0214a8STinghan Shen int ret; 1311f0214a8STinghan Shen 1321f0214a8STinghan Shen mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); 1331f0214a8STinghan Shen if (!mem_region) { 1341f0214a8STinghan Shen dev_err(dev, "no dma memory-region phandle\n"); 1351f0214a8STinghan Shen return -ENODEV; 1361f0214a8STinghan Shen } 1371f0214a8STinghan Shen 1381f0214a8STinghan Shen ret = of_address_to_resource(mem_region, 0, &res); 1391f0214a8STinghan Shen of_node_put(mem_region); 1401f0214a8STinghan Shen if (ret) { 1411f0214a8STinghan Shen dev_err(dev, "of_address_to_resource dma failed\n"); 1421f0214a8STinghan Shen return ret; 1431f0214a8STinghan Shen } 1441f0214a8STinghan Shen 1451f0214a8STinghan Shen dev_dbg(dev, "DMA %pR\n", &res); 1461f0214a8STinghan Shen 1471f0214a8STinghan Shen ret = of_reserved_mem_device_init(dev); 1481f0214a8STinghan Shen if (ret) { 1491f0214a8STinghan Shen dev_err(dev, "of_reserved_mem_device_init failed\n"); 1501f0214a8STinghan Shen return ret; 1511f0214a8STinghan Shen } 1521f0214a8STinghan Shen 1531f0214a8STinghan Shen mem_region = of_parse_phandle(dev->of_node, "memory-region", 1); 1541f0214a8STinghan Shen if (!mem_region) { 1551f0214a8STinghan Shen dev_err(dev, "no memory-region sysmem phandle\n"); 1561f0214a8STinghan Shen return -ENODEV; 1571f0214a8STinghan Shen } 1581f0214a8STinghan Shen 1591f0214a8STinghan Shen ret = of_address_to_resource(mem_region, 0, &res); 1601f0214a8STinghan Shen of_node_put(mem_region); 1611f0214a8STinghan Shen if (ret) { 1621f0214a8STinghan Shen dev_err(dev, "of_address_to_resource sysmem failed\n"); 1631f0214a8STinghan Shen return ret; 1641f0214a8STinghan Shen } 1651f0214a8STinghan Shen 1661f0214a8STinghan Shen adsp->pa_dram = (phys_addr_t)res.start; 1671f0214a8STinghan Shen if (adsp->pa_dram & DRAM_REMAP_MASK) { 1681f0214a8STinghan Shen dev_err(dev, "adsp memory(%#x) is not 4K-aligned\n", 1691f0214a8STinghan Shen (u32)adsp->pa_dram); 1701f0214a8STinghan Shen return -EINVAL; 1711f0214a8STinghan Shen } 1721f0214a8STinghan Shen 1731f0214a8STinghan Shen adsp->dramsize = resource_size(&res); 1741f0214a8STinghan Shen if (adsp->dramsize < TOTAL_SIZE_SHARED_DRAM_FROM_TAIL) { 1751f0214a8STinghan Shen dev_err(dev, "adsp memory(%#x) is not enough for share\n", 1761f0214a8STinghan Shen adsp->dramsize); 1771f0214a8STinghan Shen return -EINVAL; 1781f0214a8STinghan Shen } 1791f0214a8STinghan Shen 1801f0214a8STinghan Shen dev_dbg(dev, "dram pbase=%pa size=%#x\n", &adsp->pa_dram, adsp->dramsize); 1811f0214a8STinghan Shen 1821f0214a8STinghan Shen mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 1831f0214a8STinghan Shen if (!mmio) { 1841f0214a8STinghan Shen dev_err(dev, "no ADSP-CFG register resource\n"); 1851f0214a8STinghan Shen return -ENXIO; 1861f0214a8STinghan Shen } 1871f0214a8STinghan Shen 1881f0214a8STinghan Shen adsp->va_cfgreg = devm_ioremap_resource(dev, mmio); 1891f0214a8STinghan Shen if (IS_ERR(adsp->va_cfgreg)) 1901f0214a8STinghan Shen return PTR_ERR(adsp->va_cfgreg); 1911f0214a8STinghan Shen 1921f0214a8STinghan Shen adsp->pa_cfgreg = (phys_addr_t)mmio->start; 1931f0214a8STinghan Shen adsp->cfgregsize = resource_size(mmio); 1941f0214a8STinghan Shen 1951f0214a8STinghan Shen dev_dbg(dev, "cfgreg pbase=%pa size=%#x\n", &adsp->pa_cfgreg, adsp->cfgregsize); 1961f0214a8STinghan Shen 1971f0214a8STinghan Shen mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); 1981f0214a8STinghan Shen if (!mmio) { 1991f0214a8STinghan Shen dev_err(dev, "no SRAM resource\n"); 2001f0214a8STinghan Shen return -ENXIO; 2011f0214a8STinghan Shen } 2021f0214a8STinghan Shen 2031f0214a8STinghan Shen adsp->pa_sram = (phys_addr_t)mmio->start; 2041f0214a8STinghan Shen adsp->sramsize = resource_size(mmio); 2051f0214a8STinghan Shen 2061f0214a8STinghan Shen dev_dbg(dev, "sram pbase=%pa size=%#x\n", &adsp->pa_sram, adsp->sramsize); 2071f0214a8STinghan Shen 2081f0214a8STinghan Shen mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sec"); 2091f0214a8STinghan Shen if (!mmio) { 2101f0214a8STinghan Shen dev_err(dev, "no SEC register resource\n"); 2111f0214a8STinghan Shen return -ENXIO; 2121f0214a8STinghan Shen } 2131f0214a8STinghan Shen 2141f0214a8STinghan Shen adsp->va_secreg = devm_ioremap_resource(dev, mmio); 2151f0214a8STinghan Shen if (IS_ERR(adsp->va_secreg)) 2161f0214a8STinghan Shen return PTR_ERR(adsp->va_secreg); 2171f0214a8STinghan Shen 2181f0214a8STinghan Shen adsp->pa_secreg = (phys_addr_t)mmio->start; 2191f0214a8STinghan Shen adsp->secregsize = resource_size(mmio); 2201f0214a8STinghan Shen 2211f0214a8STinghan Shen dev_dbg(dev, "secreg pbase=%pa size=%#x\n", &adsp->pa_secreg, adsp->secregsize); 2221f0214a8STinghan Shen 2231f0214a8STinghan Shen mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bus"); 2241f0214a8STinghan Shen if (!mmio) { 2251f0214a8STinghan Shen dev_err(dev, "no BUS register resource\n"); 2261f0214a8STinghan Shen return -ENXIO; 2271f0214a8STinghan Shen } 2281f0214a8STinghan Shen 2291f0214a8STinghan Shen adsp->va_busreg = devm_ioremap_resource(dev, mmio); 2301f0214a8STinghan Shen if (IS_ERR(adsp->va_busreg)) 2311f0214a8STinghan Shen return PTR_ERR(adsp->va_busreg); 2321f0214a8STinghan Shen 2331f0214a8STinghan Shen adsp->pa_busreg = (phys_addr_t)mmio->start; 2341f0214a8STinghan Shen adsp->busregsize = resource_size(mmio); 2351f0214a8STinghan Shen 2361f0214a8STinghan Shen dev_dbg(dev, "busreg pbase=%pa size=%#x\n", &adsp->pa_busreg, adsp->busregsize); 2371f0214a8STinghan Shen 2381f0214a8STinghan Shen return 0; 2391f0214a8STinghan Shen } 2401f0214a8STinghan Shen 2411f0214a8STinghan Shen static void adsp_sram_power_on(struct snd_sof_dev *sdev) 2421f0214a8STinghan Shen { 2431f0214a8STinghan Shen snd_sof_dsp_update_bits(sdev, DSP_BUSREG_BAR, ADSP_SRAM_POOL_CON, 2441f0214a8STinghan Shen DSP_SRAM_POOL_PD_MASK, 0); 2451f0214a8STinghan Shen } 2461f0214a8STinghan Shen 2471f0214a8STinghan Shen static void adsp_sram_power_off(struct snd_sof_dev *sdev) 2481f0214a8STinghan Shen { 2491f0214a8STinghan Shen snd_sof_dsp_update_bits(sdev, DSP_BUSREG_BAR, ADSP_SRAM_POOL_CON, 2501f0214a8STinghan Shen DSP_SRAM_POOL_PD_MASK, DSP_SRAM_POOL_PD_MASK); 2511f0214a8STinghan Shen } 2521f0214a8STinghan Shen 2531f0214a8STinghan Shen /* Init the basic DSP DRAM address */ 2541f0214a8STinghan Shen static int adsp_memory_remap_init(struct snd_sof_dev *sdev, struct mtk_adsp_chip_info *adsp) 2551f0214a8STinghan Shen { 2561f0214a8STinghan Shen u32 offset; 2571f0214a8STinghan Shen 2581f0214a8STinghan Shen offset = adsp->pa_dram - DRAM_PHYS_BASE_FROM_DSP_VIEW; 2591f0214a8STinghan Shen adsp->dram_offset = offset; 2601f0214a8STinghan Shen offset >>= DRAM_REMAP_SHIFT; 2611f0214a8STinghan Shen 2621f0214a8STinghan Shen dev_dbg(sdev->dev, "adsp->pa_dram %pa, offset %#x\n", &adsp->pa_dram, offset); 2631f0214a8STinghan Shen 2641f0214a8STinghan Shen snd_sof_dsp_write(sdev, DSP_BUSREG_BAR, DSP_C0_EMI_MAP_ADDR, offset); 2651f0214a8STinghan Shen snd_sof_dsp_write(sdev, DSP_BUSREG_BAR, DSP_C0_DMAEMI_MAP_ADDR, offset); 2661f0214a8STinghan Shen 2671f0214a8STinghan Shen if (offset != snd_sof_dsp_read(sdev, DSP_BUSREG_BAR, DSP_C0_EMI_MAP_ADDR) || 2681f0214a8STinghan Shen offset != snd_sof_dsp_read(sdev, DSP_BUSREG_BAR, DSP_C0_DMAEMI_MAP_ADDR)) { 2691f0214a8STinghan Shen dev_err(sdev->dev, "emi remap fail\n"); 2701f0214a8STinghan Shen return -EIO; 2711f0214a8STinghan Shen } 2721f0214a8STinghan Shen 2731f0214a8STinghan Shen return 0; 2741f0214a8STinghan Shen } 2751f0214a8STinghan Shen 2761f0214a8STinghan Shen static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) 2771f0214a8STinghan Shen { 2781f0214a8STinghan Shen struct device *dev = &pdev->dev; 2791f0214a8STinghan Shen struct mtk_adsp_chip_info *adsp = data; 2801f0214a8STinghan Shen u32 shared_size; 2811f0214a8STinghan Shen 2821f0214a8STinghan Shen /* remap shared-dram base to be non-cachable */ 2831f0214a8STinghan Shen shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; 2841f0214a8STinghan Shen adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; 2851f0214a8STinghan Shen if (adsp->va_dram) { 2861f0214a8STinghan Shen adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; 2871f0214a8STinghan Shen } else { 2881f0214a8STinghan Shen adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, 2891f0214a8STinghan Shen shared_size); 2901f0214a8STinghan Shen if (!adsp->shared_dram) { 2911f0214a8STinghan Shen dev_err(dev, "ioremap failed for shared DRAM\n"); 2921f0214a8STinghan Shen return -ENOMEM; 2931f0214a8STinghan Shen } 2941f0214a8STinghan Shen } 2951f0214a8STinghan Shen dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", 2961f0214a8STinghan Shen adsp->shared_dram, &adsp->pa_shared_dram, shared_size); 2971f0214a8STinghan Shen 2981f0214a8STinghan Shen return 0; 2991f0214a8STinghan Shen } 3001f0214a8STinghan Shen 301570c14dcSTinghan Shen static int mt8186_run(struct snd_sof_dev *sdev) 302570c14dcSTinghan Shen { 303570c14dcSTinghan Shen u32 adsp_bootup_addr; 304570c14dcSTinghan Shen 305570c14dcSTinghan Shen adsp_bootup_addr = SRAM_PHYS_BASE_FROM_DSP_VIEW; 306570c14dcSTinghan Shen dev_dbg(sdev->dev, "HIFIxDSP boot from base : 0x%08X\n", adsp_bootup_addr); 3079ce170dcSTinghan Shen mt8186_sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); 308570c14dcSTinghan Shen 309570c14dcSTinghan Shen return 0; 310570c14dcSTinghan Shen } 311570c14dcSTinghan Shen 3121f0214a8STinghan Shen static int mt8186_dsp_probe(struct snd_sof_dev *sdev) 3131f0214a8STinghan Shen { 3141f0214a8STinghan Shen struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); 3151f0214a8STinghan Shen struct adsp_priv *priv; 3161f0214a8STinghan Shen int ret; 3171f0214a8STinghan Shen 3181f0214a8STinghan Shen priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 3191f0214a8STinghan Shen if (!priv) 3201f0214a8STinghan Shen return -ENOMEM; 3211f0214a8STinghan Shen 3221f0214a8STinghan Shen sdev->pdata->hw_pdata = priv; 3231f0214a8STinghan Shen priv->dev = sdev->dev; 3241f0214a8STinghan Shen priv->sdev = sdev; 3251f0214a8STinghan Shen 3261f0214a8STinghan Shen priv->adsp = devm_kzalloc(&pdev->dev, sizeof(struct mtk_adsp_chip_info), GFP_KERNEL); 3271f0214a8STinghan Shen if (!priv->adsp) 3281f0214a8STinghan Shen return -ENOMEM; 3291f0214a8STinghan Shen 3301f0214a8STinghan Shen ret = platform_parse_resource(pdev, priv->adsp); 3311f0214a8STinghan Shen if (ret) 3321f0214a8STinghan Shen return ret; 3331f0214a8STinghan Shen 3341f0214a8STinghan Shen sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, 3351f0214a8STinghan Shen priv->adsp->pa_sram, 3361f0214a8STinghan Shen priv->adsp->sramsize); 3371f0214a8STinghan Shen if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { 3381f0214a8STinghan Shen dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", 3391f0214a8STinghan Shen &priv->adsp->pa_sram, priv->adsp->sramsize); 3401f0214a8STinghan Shen return -ENOMEM; 3411f0214a8STinghan Shen } 3421f0214a8STinghan Shen 3431f0214a8STinghan Shen sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, 3441f0214a8STinghan Shen priv->adsp->pa_dram, 3451f0214a8STinghan Shen priv->adsp->dramsize); 3461f0214a8STinghan Shen if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { 3471f0214a8STinghan Shen dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", 3481f0214a8STinghan Shen &priv->adsp->pa_dram, priv->adsp->dramsize); 3491f0214a8STinghan Shen return -ENOMEM; 3501f0214a8STinghan Shen } 3511f0214a8STinghan Shen 3521f0214a8STinghan Shen priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; 3531f0214a8STinghan Shen 3541f0214a8STinghan Shen ret = adsp_shared_base_ioremap(pdev, priv->adsp); 3551f0214a8STinghan Shen if (ret) { 3561f0214a8STinghan Shen dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); 3571f0214a8STinghan Shen return ret; 3581f0214a8STinghan Shen } 3591f0214a8STinghan Shen 3601f0214a8STinghan Shen sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; 3611f0214a8STinghan Shen sdev->bar[DSP_SECREG_BAR] = priv->adsp->va_secreg; 3621f0214a8STinghan Shen sdev->bar[DSP_BUSREG_BAR] = priv->adsp->va_busreg; 3631f0214a8STinghan Shen 3641f0214a8STinghan Shen sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; 3651f0214a8STinghan Shen sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; 3661f0214a8STinghan Shen 367e0100bfdSTinghan Shen /* set default mailbox offset for FW ready message */ 368e0100bfdSTinghan Shen sdev->dsp_box.offset = mt8186_get_mailbox_offset(sdev); 369e0100bfdSTinghan Shen 3701f0214a8STinghan Shen ret = adsp_memory_remap_init(sdev, priv->adsp); 3711f0214a8STinghan Shen if (ret) { 3721f0214a8STinghan Shen dev_err(sdev->dev, "adsp_memory_remap_init fail!\n"); 3731f0214a8STinghan Shen return ret; 3741f0214a8STinghan Shen } 3751f0214a8STinghan Shen 376210b3ab9STinghan Shen /* enable adsp clock before touching registers */ 377210b3ab9STinghan Shen ret = mt8186_adsp_init_clock(sdev); 378210b3ab9STinghan Shen if (ret) { 379210b3ab9STinghan Shen dev_err(sdev->dev, "mt8186_adsp_init_clock failed\n"); 380210b3ab9STinghan Shen return ret; 381210b3ab9STinghan Shen } 382210b3ab9STinghan Shen 3839ce170dcSTinghan Shen ret = mt8186_adsp_clock_on(sdev); 384210b3ab9STinghan Shen if (ret) { 3859ce170dcSTinghan Shen dev_err(sdev->dev, "mt8186_adsp_clock_on fail!\n"); 386210b3ab9STinghan Shen return ret; 387210b3ab9STinghan Shen } 388210b3ab9STinghan Shen 3891f0214a8STinghan Shen adsp_sram_power_on(sdev); 3901f0214a8STinghan Shen 391e0100bfdSTinghan Shen priv->ipc_dev = platform_device_register_data(&pdev->dev, "mtk-adsp-ipc", 392e0100bfdSTinghan Shen PLATFORM_DEVID_NONE, 393e0100bfdSTinghan Shen pdev, sizeof(*pdev)); 394e0100bfdSTinghan Shen if (IS_ERR(priv->ipc_dev)) { 395*427eb3e1SDan Carpenter ret = PTR_ERR(priv->ipc_dev); 396e0100bfdSTinghan Shen dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n"); 397e0100bfdSTinghan Shen goto err_adsp_off; 398e0100bfdSTinghan Shen } 399e0100bfdSTinghan Shen 400e0100bfdSTinghan Shen priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); 401e0100bfdSTinghan Shen if (!priv->dsp_ipc) { 402e0100bfdSTinghan Shen ret = -EPROBE_DEFER; 403e0100bfdSTinghan Shen dev_err(sdev->dev, "failed to get drvdata\n"); 404e0100bfdSTinghan Shen goto exit_pdev_unregister; 405e0100bfdSTinghan Shen } 406e0100bfdSTinghan Shen 407e0100bfdSTinghan Shen mtk_adsp_ipc_set_data(priv->dsp_ipc, priv); 408e0100bfdSTinghan Shen priv->dsp_ipc->ops = &dsp_ops; 409e0100bfdSTinghan Shen 4101f0214a8STinghan Shen return 0; 411e0100bfdSTinghan Shen 412e0100bfdSTinghan Shen exit_pdev_unregister: 413e0100bfdSTinghan Shen platform_device_unregister(priv->ipc_dev); 414e0100bfdSTinghan Shen err_adsp_off: 415e0100bfdSTinghan Shen adsp_sram_power_off(sdev); 416e0100bfdSTinghan Shen mt8186_adsp_clock_off(sdev); 417e0100bfdSTinghan Shen 418e0100bfdSTinghan Shen return ret; 4191f0214a8STinghan Shen } 4201f0214a8STinghan Shen 4211f0214a8STinghan Shen static int mt8186_dsp_remove(struct snd_sof_dev *sdev) 4221f0214a8STinghan Shen { 423e0100bfdSTinghan Shen struct adsp_priv *priv = sdev->pdata->hw_pdata; 424e0100bfdSTinghan Shen 425e0100bfdSTinghan Shen platform_device_unregister(priv->ipc_dev); 4269ce170dcSTinghan Shen mt8186_sof_hifixdsp_shutdown(sdev); 4271f0214a8STinghan Shen adsp_sram_power_off(sdev); 4289ce170dcSTinghan Shen mt8186_adsp_clock_off(sdev); 4291f0214a8STinghan Shen 4301f0214a8STinghan Shen return 0; 4311f0214a8STinghan Shen } 4321f0214a8STinghan Shen 4330e0b83ccSTinghan Shen static int mt8186_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) 4340e0b83ccSTinghan Shen { 4359ce170dcSTinghan Shen mt8186_sof_hifixdsp_shutdown(sdev); 4360e0b83ccSTinghan Shen adsp_sram_power_off(sdev); 4379ce170dcSTinghan Shen mt8186_adsp_clock_off(sdev); 4380e0b83ccSTinghan Shen 4390e0b83ccSTinghan Shen return 0; 4400e0b83ccSTinghan Shen } 4410e0b83ccSTinghan Shen 4420e0b83ccSTinghan Shen static int mt8186_dsp_resume(struct snd_sof_dev *sdev) 4430e0b83ccSTinghan Shen { 4440e0b83ccSTinghan Shen int ret; 4450e0b83ccSTinghan Shen 4469ce170dcSTinghan Shen ret = mt8186_adsp_clock_on(sdev); 4470e0b83ccSTinghan Shen if (ret) { 4489ce170dcSTinghan Shen dev_err(sdev->dev, "mt8186_adsp_clock_on fail!\n"); 4490e0b83ccSTinghan Shen return ret; 4500e0b83ccSTinghan Shen } 4510e0b83ccSTinghan Shen 4520e0b83ccSTinghan Shen adsp_sram_power_on(sdev); 4530e0b83ccSTinghan Shen 4540e0b83ccSTinghan Shen return ret; 4550e0b83ccSTinghan Shen } 4560e0b83ccSTinghan Shen 4571f0214a8STinghan Shen /* on mt8186 there is 1 to 1 match between type and BAR idx */ 4581f0214a8STinghan Shen static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type) 4591f0214a8STinghan Shen { 4601f0214a8STinghan Shen return type; 4611f0214a8STinghan Shen } 4621f0214a8STinghan Shen 463e0100bfdSTinghan Shen static int mt8186_ipc_msg_data(struct snd_sof_dev *sdev, 464e0100bfdSTinghan Shen struct snd_pcm_substream *substream, 465e0100bfdSTinghan Shen void *p, size_t sz) 466e0100bfdSTinghan Shen { 467e0100bfdSTinghan Shen sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 468e0100bfdSTinghan Shen return 0; 469e0100bfdSTinghan Shen } 470e0100bfdSTinghan Shen 4711f0214a8STinghan Shen /* mt8186 ops */ 4721f0214a8STinghan Shen static struct snd_sof_dsp_ops sof_mt8186_ops = { 4731f0214a8STinghan Shen /* probe and remove */ 4741f0214a8STinghan Shen .probe = mt8186_dsp_probe, 4751f0214a8STinghan Shen .remove = mt8186_dsp_remove, 4761f0214a8STinghan Shen 477570c14dcSTinghan Shen /* DSP core boot */ 478570c14dcSTinghan Shen .run = mt8186_run, 479570c14dcSTinghan Shen 4801f0214a8STinghan Shen /* Block IO */ 4811f0214a8STinghan Shen .block_read = sof_block_read, 4821f0214a8STinghan Shen .block_write = sof_block_write, 4831f0214a8STinghan Shen 4841f0214a8STinghan Shen /* Register IO */ 4851f0214a8STinghan Shen .write = sof_io_write, 4861f0214a8STinghan Shen .read = sof_io_read, 4871f0214a8STinghan Shen .write64 = sof_io_write64, 4881f0214a8STinghan Shen .read64 = sof_io_read64, 4891f0214a8STinghan Shen 490e0100bfdSTinghan Shen /* ipc */ 491e0100bfdSTinghan Shen .send_msg = mt8186_send_msg, 492e0100bfdSTinghan Shen .get_mailbox_offset = mt8186_get_mailbox_offset, 493e0100bfdSTinghan Shen .get_window_offset = mt8186_get_window_offset, 494e0100bfdSTinghan Shen .ipc_msg_data = mt8186_ipc_msg_data, 495e0100bfdSTinghan Shen .set_stream_data_offset = sof_set_stream_data_offset, 496e0100bfdSTinghan Shen 4971f0214a8STinghan Shen /* misc */ 4981f0214a8STinghan Shen .get_bar_index = mt8186_get_bar_index, 4991f0214a8STinghan Shen 500570c14dcSTinghan Shen /* firmware loading */ 501570c14dcSTinghan Shen .load_firmware = snd_sof_load_firmware_memcpy, 502570c14dcSTinghan Shen 5031f0214a8STinghan Shen /* Firmware ops */ 5041f0214a8STinghan Shen .dsp_arch_ops = &sof_xtensa_arch_ops, 5051f0214a8STinghan Shen 5060e0b83ccSTinghan Shen /* PM */ 5070e0b83ccSTinghan Shen .suspend = mt8186_dsp_suspend, 5080e0b83ccSTinghan Shen .resume = mt8186_dsp_resume, 5090e0b83ccSTinghan Shen 5101f0214a8STinghan Shen /* ALSA HW info flags */ 5111f0214a8STinghan Shen .hw_info = SNDRV_PCM_INFO_MMAP | 5121f0214a8STinghan Shen SNDRV_PCM_INFO_MMAP_VALID | 5131f0214a8STinghan Shen SNDRV_PCM_INFO_INTERLEAVED | 5141f0214a8STinghan Shen SNDRV_PCM_INFO_PAUSE | 5151f0214a8STinghan Shen SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 5161f0214a8STinghan Shen }; 5171f0214a8STinghan Shen 5181f0214a8STinghan Shen static const struct sof_dev_desc sof_of_mt8186_desc = { 5191f0214a8STinghan Shen .ipc_supported_mask = BIT(SOF_IPC), 5201f0214a8STinghan Shen .ipc_default = SOF_IPC, 5211f0214a8STinghan Shen .default_fw_path = { 5221f0214a8STinghan Shen [SOF_IPC] = "mediatek/sof", 5231f0214a8STinghan Shen }, 5241f0214a8STinghan Shen .default_tplg_path = { 5251f0214a8STinghan Shen [SOF_IPC] = "mediatek/sof-tplg", 5261f0214a8STinghan Shen }, 5271f0214a8STinghan Shen .default_fw_filename = { 5281f0214a8STinghan Shen [SOF_IPC] = "sof-mt8186.ri", 5291f0214a8STinghan Shen }, 5301f0214a8STinghan Shen .nocodec_tplg_filename = "sof-mt8186-nocodec.tplg", 5311f0214a8STinghan Shen .ops = &sof_mt8186_ops, 5321f0214a8STinghan Shen }; 5331f0214a8STinghan Shen 5341f0214a8STinghan Shen static const struct of_device_id sof_of_mt8186_ids[] = { 5351f0214a8STinghan Shen { .compatible = "mediatek,mt8186-dsp", .data = &sof_of_mt8186_desc}, 5361f0214a8STinghan Shen { } 5371f0214a8STinghan Shen }; 5381f0214a8STinghan Shen MODULE_DEVICE_TABLE(of, sof_of_mt8186_ids); 5391f0214a8STinghan Shen 5401f0214a8STinghan Shen /* DT driver definition */ 5411f0214a8STinghan Shen static struct platform_driver snd_sof_of_mt8186_driver = { 5421f0214a8STinghan Shen .probe = sof_of_probe, 5431f0214a8STinghan Shen .remove = sof_of_remove, 5441f0214a8STinghan Shen .driver = { 5451f0214a8STinghan Shen .name = "sof-audio-of-mt8186", 5461f0214a8STinghan Shen .pm = &sof_of_pm, 5471f0214a8STinghan Shen .of_match_table = sof_of_mt8186_ids, 5481f0214a8STinghan Shen }, 5491f0214a8STinghan Shen }; 5501f0214a8STinghan Shen module_platform_driver(snd_sof_of_mt8186_driver); 5511f0214a8STinghan Shen 5521f0214a8STinghan Shen MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); 5531f0214a8STinghan Shen MODULE_IMPORT_NS(SND_SOC_SOF_MTK_COMMON); 5541f0214a8STinghan Shen MODULE_LICENSE("Dual BSD/GPL"); 555