18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * skl-message.c - HDA DSP interface for FW registration, Pipe and Module 48c2ecf20Sopenharmony_ci * configurations 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2015 Intel Corp 78c2ecf20Sopenharmony_ci * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> 88c2ecf20Sopenharmony_ci * Jeeja KP <jeeja.kp@intel.com> 98c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <sound/core.h> 158c2ecf20Sopenharmony_ci#include <sound/pcm.h> 168c2ecf20Sopenharmony_ci#include <uapi/sound/skl-tplg-interface.h> 178c2ecf20Sopenharmony_ci#include "skl-sst-dsp.h" 188c2ecf20Sopenharmony_ci#include "cnl-sst-dsp.h" 198c2ecf20Sopenharmony_ci#include "skl-sst-ipc.h" 208c2ecf20Sopenharmony_ci#include "skl.h" 218c2ecf20Sopenharmony_ci#include "../common/sst-dsp.h" 228c2ecf20Sopenharmony_ci#include "../common/sst-dsp-priv.h" 238c2ecf20Sopenharmony_ci#include "skl-topology.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int skl_alloc_dma_buf(struct device *dev, 268c2ecf20Sopenharmony_ci struct snd_dma_buffer *dmab, size_t size) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci snd_dma_free_pages(dmab); 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define SKL_ASTATE_PARAM_ID 4 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct skl_ipc_large_config_msg msg = {0}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci msg.large_param_id = SKL_ASTATE_PARAM_ID; 448c2ecf20Sopenharmony_ci msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + 458c2ecf20Sopenharmony_ci sizeof(cnt)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci skl_ipc_set_large_config(&skl->ipc, &msg, data); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int skl_dsp_setup_spib(struct device *dev, unsigned int size, 518c2ecf20Sopenharmony_ci int stream_tag, int enable) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 548c2ecf20Sopenharmony_ci struct hdac_stream *stream = snd_hdac_get_stream(bus, 558c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 568c2ecf20Sopenharmony_ci struct hdac_ext_stream *estream; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!stream) 598c2ecf20Sopenharmony_ci return -EINVAL; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci estream = stream_to_hdac_ext_stream(stream); 628c2ecf20Sopenharmony_ci /* enable/disable SPIB for this hdac stream */ 638c2ecf20Sopenharmony_ci snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* set the spib value */ 668c2ecf20Sopenharmony_ci snd_hdac_ext_stream_set_spib(bus, estream, size); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int skl_dsp_prepare(struct device *dev, unsigned int format, 728c2ecf20Sopenharmony_ci unsigned int size, struct snd_dma_buffer *dmab) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 758c2ecf20Sopenharmony_ci struct hdac_ext_stream *estream; 768c2ecf20Sopenharmony_ci struct hdac_stream *stream; 778c2ecf20Sopenharmony_ci struct snd_pcm_substream substream; 788c2ecf20Sopenharmony_ci int ret; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!bus) 818c2ecf20Sopenharmony_ci return -ENODEV; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci memset(&substream, 0, sizeof(substream)); 848c2ecf20Sopenharmony_ci substream.stream = SNDRV_PCM_STREAM_PLAYBACK; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci estream = snd_hdac_ext_stream_assign(bus, &substream, 878c2ecf20Sopenharmony_ci HDAC_EXT_STREAM_TYPE_HOST); 888c2ecf20Sopenharmony_ci if (!estream) 898c2ecf20Sopenharmony_ci return -ENODEV; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci stream = hdac_stream(estream); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* assign decouple host dma channel */ 948c2ecf20Sopenharmony_ci ret = snd_hdac_dsp_prepare(stream, format, size, dmab); 958c2ecf20Sopenharmony_ci if (ret < 0) 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci skl_dsp_setup_spib(dev, size, stream->stream_tag, true); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return stream->stream_tag; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int skl_dsp_trigger(struct device *dev, bool start, int stream_tag) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 1068c2ecf20Sopenharmony_ci struct hdac_stream *stream; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!bus) 1098c2ecf20Sopenharmony_ci return -ENODEV; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci stream = snd_hdac_get_stream(bus, 1128c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 1138c2ecf20Sopenharmony_ci if (!stream) 1148c2ecf20Sopenharmony_ci return -EINVAL; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci snd_hdac_dsp_trigger(stream, start); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int skl_dsp_cleanup(struct device *dev, 1228c2ecf20Sopenharmony_ci struct snd_dma_buffer *dmab, int stream_tag) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 1258c2ecf20Sopenharmony_ci struct hdac_stream *stream; 1268c2ecf20Sopenharmony_ci struct hdac_ext_stream *estream; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (!bus) 1298c2ecf20Sopenharmony_ci return -ENODEV; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci stream = snd_hdac_get_stream(bus, 1328c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 1338c2ecf20Sopenharmony_ci if (!stream) 1348c2ecf20Sopenharmony_ci return -EINVAL; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci estream = stream_to_hdac_ext_stream(stream); 1378c2ecf20Sopenharmony_ci skl_dsp_setup_spib(dev, 0, stream_tag, false); 1388c2ecf20Sopenharmony_ci snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci snd_hdac_dsp_cleanup(stream, dmab); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic struct skl_dsp_loader_ops skl_get_loader_ops(void) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops)); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci loader_ops.alloc_dma_buf = skl_alloc_dma_buf; 1528c2ecf20Sopenharmony_ci loader_ops.free_dma_buf = skl_free_dma_buf; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return loader_ops; 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic struct skl_dsp_loader_ops bxt_get_loader_ops(void) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci memset(&loader_ops, 0, sizeof(loader_ops)); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci loader_ops.alloc_dma_buf = skl_alloc_dma_buf; 1648c2ecf20Sopenharmony_ci loader_ops.free_dma_buf = skl_free_dma_buf; 1658c2ecf20Sopenharmony_ci loader_ops.prepare = skl_dsp_prepare; 1668c2ecf20Sopenharmony_ci loader_ops.trigger = skl_dsp_trigger; 1678c2ecf20Sopenharmony_ci loader_ops.cleanup = skl_dsp_cleanup; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return loader_ops; 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic const struct skl_dsp_ops dsp_ops[] = { 1738c2ecf20Sopenharmony_ci { 1748c2ecf20Sopenharmony_ci .id = 0x9d70, 1758c2ecf20Sopenharmony_ci .num_cores = 2, 1768c2ecf20Sopenharmony_ci .loader_ops = skl_get_loader_ops, 1778c2ecf20Sopenharmony_ci .init = skl_sst_dsp_init, 1788c2ecf20Sopenharmony_ci .init_fw = skl_sst_init_fw, 1798c2ecf20Sopenharmony_ci .cleanup = skl_sst_dsp_cleanup 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci { 1828c2ecf20Sopenharmony_ci .id = 0x9d71, 1838c2ecf20Sopenharmony_ci .num_cores = 2, 1848c2ecf20Sopenharmony_ci .loader_ops = skl_get_loader_ops, 1858c2ecf20Sopenharmony_ci .init = skl_sst_dsp_init, 1868c2ecf20Sopenharmony_ci .init_fw = skl_sst_init_fw, 1878c2ecf20Sopenharmony_ci .cleanup = skl_sst_dsp_cleanup 1888c2ecf20Sopenharmony_ci }, 1898c2ecf20Sopenharmony_ci { 1908c2ecf20Sopenharmony_ci .id = 0x5a98, 1918c2ecf20Sopenharmony_ci .num_cores = 2, 1928c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 1938c2ecf20Sopenharmony_ci .init = bxt_sst_dsp_init, 1948c2ecf20Sopenharmony_ci .init_fw = bxt_sst_init_fw, 1958c2ecf20Sopenharmony_ci .cleanup = bxt_sst_dsp_cleanup 1968c2ecf20Sopenharmony_ci }, 1978c2ecf20Sopenharmony_ci { 1988c2ecf20Sopenharmony_ci .id = 0x3198, 1998c2ecf20Sopenharmony_ci .num_cores = 2, 2008c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 2018c2ecf20Sopenharmony_ci .init = bxt_sst_dsp_init, 2028c2ecf20Sopenharmony_ci .init_fw = bxt_sst_init_fw, 2038c2ecf20Sopenharmony_ci .cleanup = bxt_sst_dsp_cleanup 2048c2ecf20Sopenharmony_ci }, 2058c2ecf20Sopenharmony_ci { 2068c2ecf20Sopenharmony_ci .id = 0x9dc8, 2078c2ecf20Sopenharmony_ci .num_cores = 4, 2088c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 2098c2ecf20Sopenharmony_ci .init = cnl_sst_dsp_init, 2108c2ecf20Sopenharmony_ci .init_fw = cnl_sst_init_fw, 2118c2ecf20Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 2128c2ecf20Sopenharmony_ci }, 2138c2ecf20Sopenharmony_ci { 2148c2ecf20Sopenharmony_ci .id = 0xa348, 2158c2ecf20Sopenharmony_ci .num_cores = 4, 2168c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 2178c2ecf20Sopenharmony_ci .init = cnl_sst_dsp_init, 2188c2ecf20Sopenharmony_ci .init_fw = cnl_sst_init_fw, 2198c2ecf20Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 2208c2ecf20Sopenharmony_ci }, 2218c2ecf20Sopenharmony_ci { 2228c2ecf20Sopenharmony_ci .id = 0x02c8, 2238c2ecf20Sopenharmony_ci .num_cores = 4, 2248c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 2258c2ecf20Sopenharmony_ci .init = cnl_sst_dsp_init, 2268c2ecf20Sopenharmony_ci .init_fw = cnl_sst_init_fw, 2278c2ecf20Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 2288c2ecf20Sopenharmony_ci }, 2298c2ecf20Sopenharmony_ci { 2308c2ecf20Sopenharmony_ci .id = 0x06c8, 2318c2ecf20Sopenharmony_ci .num_cores = 4, 2328c2ecf20Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 2338c2ecf20Sopenharmony_ci .init = cnl_sst_dsp_init, 2348c2ecf20Sopenharmony_ci .init_fw = cnl_sst_init_fw, 2358c2ecf20Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 2368c2ecf20Sopenharmony_ci }, 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciconst struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int i; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { 2448c2ecf20Sopenharmony_ci if (dsp_ops[i].id == pci_id) 2458c2ecf20Sopenharmony_ci return &dsp_ops[i]; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return NULL; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint skl_init_dsp(struct skl_dev *skl) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci void __iomem *mmio_base; 2548c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 2558c2ecf20Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 2568c2ecf20Sopenharmony_ci int irq = bus->irq; 2578c2ecf20Sopenharmony_ci const struct skl_dsp_ops *ops; 2588c2ecf20Sopenharmony_ci struct skl_dsp_cores *cores; 2598c2ecf20Sopenharmony_ci int ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* enable ppcap interrupt */ 2628c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, true); 2638c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, true); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* read the BAR of the ADSP MMIO */ 2668c2ecf20Sopenharmony_ci mmio_base = pci_ioremap_bar(skl->pci, 4); 2678c2ecf20Sopenharmony_ci if (mmio_base == NULL) { 2688c2ecf20Sopenharmony_ci dev_err(bus->dev, "ioremap error\n"); 2698c2ecf20Sopenharmony_ci return -ENXIO; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ops = skl_get_dsp_ops(skl->pci->device); 2738c2ecf20Sopenharmony_ci if (!ops) { 2748c2ecf20Sopenharmony_ci ret = -EIO; 2758c2ecf20Sopenharmony_ci goto unmap_mmio; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci loader_ops = ops->loader_ops(); 2798c2ecf20Sopenharmony_ci ret = ops->init(bus->dev, mmio_base, irq, 2808c2ecf20Sopenharmony_ci skl->fw_name, loader_ops, 2818c2ecf20Sopenharmony_ci &skl); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (ret < 0) 2848c2ecf20Sopenharmony_ci goto unmap_mmio; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci skl->dsp_ops = ops; 2878c2ecf20Sopenharmony_ci cores = &skl->cores; 2888c2ecf20Sopenharmony_ci cores->count = ops->num_cores; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); 2918c2ecf20Sopenharmony_ci if (!cores->state) { 2928c2ecf20Sopenharmony_ci ret = -ENOMEM; 2938c2ecf20Sopenharmony_ci goto unmap_mmio; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count), 2978c2ecf20Sopenharmony_ci GFP_KERNEL); 2988c2ecf20Sopenharmony_ci if (!cores->usage_count) { 2998c2ecf20Sopenharmony_ci ret = -ENOMEM; 3008c2ecf20Sopenharmony_ci goto free_core_state; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "dsp registration status=%d\n", ret); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cifree_core_state: 3088c2ecf20Sopenharmony_ci kfree(cores->state); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciunmap_mmio: 3118c2ecf20Sopenharmony_ci iounmap(mmio_base); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return ret; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciint skl_free_dsp(struct skl_dev *skl) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* disable ppcap interrupt */ 3218c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, false); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci skl->dsp_ops->cleanup(bus->dev, skl); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci kfree(skl->cores.state); 3268c2ecf20Sopenharmony_ci kfree(skl->cores.usage_count); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (skl->dsp->addr.lpe) 3298c2ecf20Sopenharmony_ci iounmap(skl->dsp->addr.lpe); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * In the case of "suspend_active" i.e, the Audio IP being active 3368c2ecf20Sopenharmony_ci * during system suspend, immediately excecute any pending D0i3 work 3378c2ecf20Sopenharmony_ci * before suspending. This is needed for the IP to work in low power 3388c2ecf20Sopenharmony_ci * mode during system suspend. In the case of normal suspend, cancel 3398c2ecf20Sopenharmony_ci * any pending D0i3 work. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ciint skl_suspend_late_dsp(struct skl_dev *skl) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct delayed_work *dwork; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!skl) 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci dwork = &skl->d0i3.work; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (dwork->work.func) { 3518c2ecf20Sopenharmony_ci if (skl->supend_active) 3528c2ecf20Sopenharmony_ci flush_delayed_work(dwork); 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci cancel_delayed_work_sync(dwork); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciint skl_suspend_dsp(struct skl_dev *skl) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 3638c2ecf20Sopenharmony_ci int ret; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* if ppcap is not supported return 0 */ 3668c2ecf20Sopenharmony_ci if (!bus->ppcap) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = skl_dsp_sleep(skl->dsp); 3708c2ecf20Sopenharmony_ci if (ret < 0) 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* disable ppcap interrupt */ 3748c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, false); 3758c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, false); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ciint skl_resume_dsp(struct skl_dev *skl) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 3838c2ecf20Sopenharmony_ci int ret; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* if ppcap is not supported return 0 */ 3868c2ecf20Sopenharmony_ci if (!bus->ppcap) 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* enable ppcap interrupt */ 3908c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, true); 3918c2ecf20Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, true); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* check if DSP 1st boot is done */ 3948c2ecf20Sopenharmony_ci if (skl->is_first_boot) 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* 3988c2ecf20Sopenharmony_ci * Disable dynamic clock and power gating during firmware 3998c2ecf20Sopenharmony_ci * and library download 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci skl->enable_miscbdcge(skl->dev, false); 4028c2ecf20Sopenharmony_ci skl->clock_power_gating(skl->dev, false); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ret = skl_dsp_wake(skl->dsp); 4058c2ecf20Sopenharmony_ci skl->enable_miscbdcge(skl->dev, true); 4068c2ecf20Sopenharmony_ci skl->clock_power_gating(skl->dev, true); 4078c2ecf20Sopenharmony_ci if (ret < 0) 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (skl->cfg.astate_cfg != NULL) { 4118c2ecf20Sopenharmony_ci skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, 4128c2ecf20Sopenharmony_ci skl->cfg.astate_cfg); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cienum skl_bitdepth skl_get_bit_depth(int params) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci switch (params) { 4208c2ecf20Sopenharmony_ci case 8: 4218c2ecf20Sopenharmony_ci return SKL_DEPTH_8BIT; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci case 16: 4248c2ecf20Sopenharmony_ci return SKL_DEPTH_16BIT; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci case 24: 4278c2ecf20Sopenharmony_ci return SKL_DEPTH_24BIT; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci case 32: 4308c2ecf20Sopenharmony_ci return SKL_DEPTH_32BIT; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci default: 4338c2ecf20Sopenharmony_ci return SKL_DEPTH_INVALID; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* 4398c2ecf20Sopenharmony_ci * Each module in DSP expects a base module configuration, which consists of 4408c2ecf20Sopenharmony_ci * PCM format information, which we calculate in driver and resource values 4418c2ecf20Sopenharmony_ci * which are read from widget information passed through topology binary 4428c2ecf20Sopenharmony_ci * This is send when we create a module with INIT_INSTANCE IPC msg 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_cistatic void skl_set_base_module_format(struct skl_dev *skl, 4458c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 4468c2ecf20Sopenharmony_ci struct skl_base_cfg *base_cfg) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct skl_module *module = mconfig->module; 4498c2ecf20Sopenharmony_ci struct skl_module_res *res = &module->resources[mconfig->res_idx]; 4508c2ecf20Sopenharmony_ci struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; 4518c2ecf20Sopenharmony_ci struct skl_module_fmt *format = &fmt->inputs[0].fmt; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci base_cfg->audio_fmt.number_of_channels = format->channels; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci base_cfg->audio_fmt.s_freq = format->s_freq; 4568c2ecf20Sopenharmony_ci base_cfg->audio_fmt.bit_depth = format->bit_depth; 4578c2ecf20Sopenharmony_ci base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; 4588c2ecf20Sopenharmony_ci base_cfg->audio_fmt.ch_cfg = format->ch_cfg; 4598c2ecf20Sopenharmony_ci base_cfg->audio_fmt.sample_type = format->sample_type; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", 4628c2ecf20Sopenharmony_ci format->bit_depth, format->valid_bit_depth, 4638c2ecf20Sopenharmony_ci format->ch_cfg); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci base_cfg->audio_fmt.channel_map = format->ch_map; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci base_cfg->audio_fmt.interleaving = format->interleaving_style; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci base_cfg->cpc = res->cpc; 4708c2ecf20Sopenharmony_ci base_cfg->ibs = res->ibs; 4718c2ecf20Sopenharmony_ci base_cfg->obs = res->obs; 4728c2ecf20Sopenharmony_ci base_cfg->is_pages = res->is_pages; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * Copies copier capabilities into copier module and updates copier module 4778c2ecf20Sopenharmony_ci * config size. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_cistatic void skl_copy_copier_caps(struct skl_module_cfg *mconfig, 4808c2ecf20Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size == 0) 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci memcpy(cpr_mconfig->gtw_cfg.config_data, 4868c2ecf20Sopenharmony_ci mconfig->formats_config.caps, 4878c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.config_length = 4908c2ecf20Sopenharmony_ci (mconfig->formats_config.caps_size) / 4; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF 4948c2ecf20Sopenharmony_ci/* 4958c2ecf20Sopenharmony_ci * Calculate the gatewat settings required for copier module, type of 4968c2ecf20Sopenharmony_ci * gateway and index of gateway to use 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_cistatic u32 skl_get_node_id(struct skl_dev *skl, 4998c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci union skl_connector_node_id node_id = {0}; 5028c2ecf20Sopenharmony_ci union skl_ssp_dma_node ssp_node = {0}; 5038c2ecf20Sopenharmony_ci struct skl_pipe_params *params = mconfig->pipe->p_params; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci switch (mconfig->dev_type) { 5068c2ecf20Sopenharmony_ci case SKL_DEVICE_BT: 5078c2ecf20Sopenharmony_ci node_id.node.dma_type = 5088c2ecf20Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 5098c2ecf20Sopenharmony_ci SKL_DMA_I2S_LINK_OUTPUT_CLASS : 5108c2ecf20Sopenharmony_ci SKL_DMA_I2S_LINK_INPUT_CLASS; 5118c2ecf20Sopenharmony_ci node_id.node.vindex = params->host_dma_id + 5128c2ecf20Sopenharmony_ci (mconfig->vbus_id << 3); 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci case SKL_DEVICE_I2S: 5168c2ecf20Sopenharmony_ci node_id.node.dma_type = 5178c2ecf20Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 5188c2ecf20Sopenharmony_ci SKL_DMA_I2S_LINK_OUTPUT_CLASS : 5198c2ecf20Sopenharmony_ci SKL_DMA_I2S_LINK_INPUT_CLASS; 5208c2ecf20Sopenharmony_ci ssp_node.dma_node.time_slot_index = mconfig->time_slot; 5218c2ecf20Sopenharmony_ci ssp_node.dma_node.i2s_instance = mconfig->vbus_id; 5228c2ecf20Sopenharmony_ci node_id.node.vindex = ssp_node.val; 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci case SKL_DEVICE_DMIC: 5268c2ecf20Sopenharmony_ci node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS; 5278c2ecf20Sopenharmony_ci node_id.node.vindex = mconfig->vbus_id + 5288c2ecf20Sopenharmony_ci (mconfig->time_slot); 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci case SKL_DEVICE_HDALINK: 5328c2ecf20Sopenharmony_ci node_id.node.dma_type = 5338c2ecf20Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 5348c2ecf20Sopenharmony_ci SKL_DMA_HDA_LINK_OUTPUT_CLASS : 5358c2ecf20Sopenharmony_ci SKL_DMA_HDA_LINK_INPUT_CLASS; 5368c2ecf20Sopenharmony_ci node_id.node.vindex = params->link_dma_id; 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci case SKL_DEVICE_HDAHOST: 5408c2ecf20Sopenharmony_ci node_id.node.dma_type = 5418c2ecf20Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 5428c2ecf20Sopenharmony_ci SKL_DMA_HDA_HOST_OUTPUT_CLASS : 5438c2ecf20Sopenharmony_ci SKL_DMA_HDA_HOST_INPUT_CLASS; 5448c2ecf20Sopenharmony_ci node_id.node.vindex = params->host_dma_id; 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci default: 5488c2ecf20Sopenharmony_ci node_id.val = 0xFFFFFFFF; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return node_id.val; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, 5568c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 5578c2ecf20Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u32 dma_io_buf; 5608c2ecf20Sopenharmony_ci struct skl_module_res *res; 5618c2ecf20Sopenharmony_ci int res_idx = mconfig->res_idx; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { 5668c2ecf20Sopenharmony_ci cpr_mconfig->cpr_feature_mask = 0; 5678c2ecf20Sopenharmony_ci return; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (skl->nr_modules) { 5718c2ecf20Sopenharmony_ci res = &mconfig->module->resources[mconfig->res_idx]; 5728c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size; 5738c2ecf20Sopenharmony_ci goto skip_buf_size_calc; 5748c2ecf20Sopenharmony_ci } else { 5758c2ecf20Sopenharmony_ci res = &mconfig->module->resources[res_idx]; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci switch (mconfig->hw_conn_type) { 5798c2ecf20Sopenharmony_ci case SKL_CONN_SOURCE: 5808c2ecf20Sopenharmony_ci if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 5818c2ecf20Sopenharmony_ci dma_io_buf = res->ibs; 5828c2ecf20Sopenharmony_ci else 5838c2ecf20Sopenharmony_ci dma_io_buf = res->obs; 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci case SKL_CONN_SINK: 5878c2ecf20Sopenharmony_ci if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 5888c2ecf20Sopenharmony_ci dma_io_buf = res->obs; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci dma_io_buf = res->ibs; 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci default: 5948c2ecf20Sopenharmony_ci dev_warn(skl->dev, "wrong connection type: %d\n", 5958c2ecf20Sopenharmony_ci mconfig->hw_conn_type); 5968c2ecf20Sopenharmony_ci return; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 6008c2ecf20Sopenharmony_ci mconfig->dma_buffer_size * dma_io_buf; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* fallback to 2ms default value */ 6038c2ecf20Sopenharmony_ci if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { 6048c2ecf20Sopenharmony_ci if (mconfig->hw_conn_type == SKL_CONN_SOURCE) 6058c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs; 6068c2ecf20Sopenharmony_ci else 6078c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciskip_buf_size_calc: 6118c2ecf20Sopenharmony_ci cpr_mconfig->cpr_feature_mask = 0; 6128c2ecf20Sopenharmony_ci cpr_mconfig->gtw_cfg.config_length = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci skl_copy_copier_caps(mconfig, cpr_mconfig); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci#define DMA_CONTROL_ID 5 6188c2ecf20Sopenharmony_ci#define DMA_I2S_BLOB_SIZE 21 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciint skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, 6218c2ecf20Sopenharmony_ci u32 caps_size, u32 node_id) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct skl_dma_control *dma_ctrl; 6248c2ecf20Sopenharmony_ci struct skl_ipc_large_config_msg msg = {0}; 6258c2ecf20Sopenharmony_ci int err = 0; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * if blob size zero, then return 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci if (caps_size == 0) 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci msg.large_param_id = DMA_CONTROL_ID; 6358c2ecf20Sopenharmony_ci msg.param_data_size = sizeof(struct skl_dma_control) + caps_size; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL); 6388c2ecf20Sopenharmony_ci if (dma_ctrl == NULL) 6398c2ecf20Sopenharmony_ci return -ENOMEM; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci dma_ctrl->node_id = node_id; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * NHLT blob may contain additional configs along with i2s blob. 6458c2ecf20Sopenharmony_ci * firmware expects only the i2s blob size as the config_length. 6468c2ecf20Sopenharmony_ci * So fix to i2s blob size. 6478c2ecf20Sopenharmony_ci * size in dwords. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci dma_ctrl->config_length = DMA_I2S_BLOB_SIZE; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci memcpy(dma_ctrl->config_data, caps, caps_size); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci kfree(dma_ctrl); 6568c2ecf20Sopenharmony_ci return err; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void skl_setup_out_format(struct skl_dev *skl, 6618c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 6628c2ecf20Sopenharmony_ci struct skl_audio_data_format *out_fmt) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct skl_module *module = mconfig->module; 6658c2ecf20Sopenharmony_ci struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; 6668c2ecf20Sopenharmony_ci struct skl_module_fmt *format = &fmt->outputs[0].fmt; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci out_fmt->number_of_channels = (u8)format->channels; 6698c2ecf20Sopenharmony_ci out_fmt->s_freq = format->s_freq; 6708c2ecf20Sopenharmony_ci out_fmt->bit_depth = format->bit_depth; 6718c2ecf20Sopenharmony_ci out_fmt->valid_bit_depth = format->valid_bit_depth; 6728c2ecf20Sopenharmony_ci out_fmt->ch_cfg = format->ch_cfg; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci out_fmt->channel_map = format->ch_map; 6758c2ecf20Sopenharmony_ci out_fmt->interleaving = format->interleaving_style; 6768c2ecf20Sopenharmony_ci out_fmt->sample_type = format->sample_type; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", 6798c2ecf20Sopenharmony_ci out_fmt->number_of_channels, format->s_freq, format->bit_depth); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/* 6838c2ecf20Sopenharmony_ci * DSP needs SRC module for frequency conversion, SRC takes base module 6848c2ecf20Sopenharmony_ci * configuration and the target frequency as extra parameter passed as src 6858c2ecf20Sopenharmony_ci * config 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cistatic void skl_set_src_format(struct skl_dev *skl, 6888c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 6898c2ecf20Sopenharmony_ci struct skl_src_module_cfg *src_mconfig) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct skl_module *module = mconfig->module; 6928c2ecf20Sopenharmony_ci struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; 6938c2ecf20Sopenharmony_ci struct skl_module_fmt *fmt = &iface->outputs[0].fmt; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, mconfig, 6968c2ecf20Sopenharmony_ci (struct skl_base_cfg *)src_mconfig); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci src_mconfig->src_cfg = fmt->s_freq; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/* 7028c2ecf20Sopenharmony_ci * DSP needs updown module to do channel conversion. updown module take base 7038c2ecf20Sopenharmony_ci * module configuration and channel configuration 7048c2ecf20Sopenharmony_ci * It also take coefficients and now we have defaults applied here 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_cistatic void skl_set_updown_mixer_format(struct skl_dev *skl, 7078c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 7088c2ecf20Sopenharmony_ci struct skl_up_down_mixer_cfg *mixer_mconfig) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct skl_module *module = mconfig->module; 7118c2ecf20Sopenharmony_ci struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; 7128c2ecf20Sopenharmony_ci struct skl_module_fmt *fmt = &iface->outputs[0].fmt; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, mconfig, 7158c2ecf20Sopenharmony_ci (struct skl_base_cfg *)mixer_mconfig); 7168c2ecf20Sopenharmony_ci mixer_mconfig->out_ch_cfg = fmt->ch_cfg; 7178c2ecf20Sopenharmony_ci mixer_mconfig->ch_map = fmt->ch_map; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci/* 7218c2ecf20Sopenharmony_ci * 'copier' is DSP internal module which copies data from Host DMA (HDA host 7228c2ecf20Sopenharmony_ci * dma) or link (hda link, SSP, PDM) 7238c2ecf20Sopenharmony_ci * Here we calculate the copier module parameters, like PCM format, output 7248c2ecf20Sopenharmony_ci * format, gateway settings 7258c2ecf20Sopenharmony_ci * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_cistatic void skl_set_copier_format(struct skl_dev *skl, 7288c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 7298c2ecf20Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; 7328c2ecf20Sopenharmony_ci struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, mconfig, base_cfg); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci skl_setup_out_format(skl, mconfig, out_fmt); 7378c2ecf20Sopenharmony_ci skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci/* 7418c2ecf20Sopenharmony_ci * Algo module are DSP pre processing modules. Algo module take base module 7428c2ecf20Sopenharmony_ci * configuration and params 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void skl_set_algo_format(struct skl_dev *skl, 7468c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 7478c2ecf20Sopenharmony_ci struct skl_algo_cfg *algo_mcfg) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, mconfig, base_cfg); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (mconfig->formats_config.caps_size == 0) 7548c2ecf20Sopenharmony_ci return; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci memcpy(algo_mcfg->params, 7578c2ecf20Sopenharmony_ci mconfig->formats_config.caps, 7588c2ecf20Sopenharmony_ci mconfig->formats_config.caps_size); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/* 7638c2ecf20Sopenharmony_ci * Mic select module allows selecting one or many input channels, thus 7648c2ecf20Sopenharmony_ci * acting as a demux. 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci * Mic select module take base module configuration and out-format 7678c2ecf20Sopenharmony_ci * configuration 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_cistatic void skl_set_base_outfmt_format(struct skl_dev *skl, 7708c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig, 7718c2ecf20Sopenharmony_ci struct skl_base_outfmt_cfg *base_outfmt_mcfg) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; 7748c2ecf20Sopenharmony_ci struct skl_base_cfg *base_cfg = 7758c2ecf20Sopenharmony_ci (struct skl_base_cfg *)base_outfmt_mcfg; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, mconfig, base_cfg); 7788c2ecf20Sopenharmony_ci skl_setup_out_format(skl, mconfig, out_fmt); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic u16 skl_get_module_param_size(struct skl_dev *skl, 7828c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci u16 param_size; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci switch (mconfig->m_type) { 7878c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_COPIER: 7888c2ecf20Sopenharmony_ci param_size = sizeof(struct skl_cpr_cfg); 7898c2ecf20Sopenharmony_ci param_size += mconfig->formats_config.caps_size; 7908c2ecf20Sopenharmony_ci return param_size; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_SRCINT: 7938c2ecf20Sopenharmony_ci return sizeof(struct skl_src_module_cfg); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_UPDWMIX: 7968c2ecf20Sopenharmony_ci return sizeof(struct skl_up_down_mixer_cfg); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_ALGO: 7998c2ecf20Sopenharmony_ci param_size = sizeof(struct skl_base_cfg); 8008c2ecf20Sopenharmony_ci param_size += mconfig->formats_config.caps_size; 8018c2ecf20Sopenharmony_ci return param_size; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_BASE_OUTFMT: 8048c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_MIC_SELECT: 8058c2ecf20Sopenharmony_ci return sizeof(struct skl_base_outfmt_cfg); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_MIXER: 8088c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_KPB: 8098c2ecf20Sopenharmony_ci return sizeof(struct skl_base_cfg); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci default: 8128c2ecf20Sopenharmony_ci /* 8138c2ecf20Sopenharmony_ci * return only base cfg when no specific module type is 8148c2ecf20Sopenharmony_ci * specified 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci return sizeof(struct skl_base_cfg); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci/* 8238c2ecf20Sopenharmony_ci * DSP firmware supports various modules like copier, SRC, updown etc. 8248c2ecf20Sopenharmony_ci * These modules required various parameters to be calculated and sent for 8258c2ecf20Sopenharmony_ci * the module initialization to DSP. By default a generic module needs only 8268c2ecf20Sopenharmony_ci * base module format configuration 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic int skl_set_module_format(struct skl_dev *skl, 8308c2ecf20Sopenharmony_ci struct skl_module_cfg *module_config, 8318c2ecf20Sopenharmony_ci u16 *module_config_size, 8328c2ecf20Sopenharmony_ci void **param_data) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci u16 param_size; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci param_size = skl_get_module_param_size(skl, module_config); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci *param_data = kzalloc(param_size, GFP_KERNEL); 8398c2ecf20Sopenharmony_ci if (NULL == *param_data) 8408c2ecf20Sopenharmony_ci return -ENOMEM; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci *module_config_size = param_size; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci switch (module_config->m_type) { 8458c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_COPIER: 8468c2ecf20Sopenharmony_ci skl_set_copier_format(skl, module_config, *param_data); 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_SRCINT: 8508c2ecf20Sopenharmony_ci skl_set_src_format(skl, module_config, *param_data); 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_UPDWMIX: 8548c2ecf20Sopenharmony_ci skl_set_updown_mixer_format(skl, module_config, *param_data); 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_ALGO: 8588c2ecf20Sopenharmony_ci skl_set_algo_format(skl, module_config, *param_data); 8598c2ecf20Sopenharmony_ci break; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_BASE_OUTFMT: 8628c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_MIC_SELECT: 8638c2ecf20Sopenharmony_ci skl_set_base_outfmt_format(skl, module_config, *param_data); 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_MIXER: 8678c2ecf20Sopenharmony_ci case SKL_MODULE_TYPE_KPB: 8688c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, module_config, *param_data); 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci default: 8728c2ecf20Sopenharmony_ci skl_set_base_module_format(skl, module_config, *param_data); 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", 8788c2ecf20Sopenharmony_ci module_config->m_type, module_config->id.module_id, 8798c2ecf20Sopenharmony_ci param_size); 8808c2ecf20Sopenharmony_ci print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, 8818c2ecf20Sopenharmony_ci *param_data, param_size, false); 8828c2ecf20Sopenharmony_ci return 0; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic int skl_get_queue_index(struct skl_module_pin *mpin, 8868c2ecf20Sopenharmony_ci struct skl_module_inst_id id, int max) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci int i; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 8918c2ecf20Sopenharmony_ci if (mpin[i].id.module_id == id.module_id && 8928c2ecf20Sopenharmony_ci mpin[i].id.instance_id == id.instance_id) 8938c2ecf20Sopenharmony_ci return i; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci return -EINVAL; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci/* 9008c2ecf20Sopenharmony_ci * Allocates queue for each module. 9018c2ecf20Sopenharmony_ci * if dynamic, the pin_index is allocated 0 to max_pin. 9028c2ecf20Sopenharmony_ci * In static, the pin_index is fixed based on module_id and instance id 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_cistatic int skl_alloc_queue(struct skl_module_pin *mpin, 9058c2ecf20Sopenharmony_ci struct skl_module_cfg *tgt_cfg, int max) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci int i; 9088c2ecf20Sopenharmony_ci struct skl_module_inst_id id = tgt_cfg->id; 9098c2ecf20Sopenharmony_ci /* 9108c2ecf20Sopenharmony_ci * if pin in dynamic, find first free pin 9118c2ecf20Sopenharmony_ci * otherwise find match module and instance id pin as topology will 9128c2ecf20Sopenharmony_ci * ensure a unique pin is assigned to this so no need to 9138c2ecf20Sopenharmony_ci * allocate/free 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 9168c2ecf20Sopenharmony_ci if (mpin[i].is_dynamic) { 9178c2ecf20Sopenharmony_ci if (!mpin[i].in_use && 9188c2ecf20Sopenharmony_ci mpin[i].pin_state == SKL_PIN_UNBIND) { 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci mpin[i].in_use = true; 9218c2ecf20Sopenharmony_ci mpin[i].id.module_id = id.module_id; 9228c2ecf20Sopenharmony_ci mpin[i].id.instance_id = id.instance_id; 9238c2ecf20Sopenharmony_ci mpin[i].id.pvt_id = id.pvt_id; 9248c2ecf20Sopenharmony_ci mpin[i].tgt_mcfg = tgt_cfg; 9258c2ecf20Sopenharmony_ci return i; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci } else { 9288c2ecf20Sopenharmony_ci if (mpin[i].id.module_id == id.module_id && 9298c2ecf20Sopenharmony_ci mpin[i].id.instance_id == id.instance_id && 9308c2ecf20Sopenharmony_ci mpin[i].pin_state == SKL_PIN_UNBIND) { 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci mpin[i].tgt_mcfg = tgt_cfg; 9338c2ecf20Sopenharmony_ci return i; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic void skl_free_queue(struct skl_module_pin *mpin, int q_index) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci if (mpin[q_index].is_dynamic) { 9448c2ecf20Sopenharmony_ci mpin[q_index].in_use = false; 9458c2ecf20Sopenharmony_ci mpin[q_index].id.module_id = 0; 9468c2ecf20Sopenharmony_ci mpin[q_index].id.instance_id = 0; 9478c2ecf20Sopenharmony_ci mpin[q_index].id.pvt_id = 0; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci mpin[q_index].pin_state = SKL_PIN_UNBIND; 9508c2ecf20Sopenharmony_ci mpin[q_index].tgt_mcfg = NULL; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci/* Module state will be set to unint, if all the out pin state is UNBIND */ 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic void skl_clear_module_state(struct skl_module_pin *mpin, int max, 9568c2ecf20Sopenharmony_ci struct skl_module_cfg *mcfg) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci int i; 9598c2ecf20Sopenharmony_ci bool found = false; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 9628c2ecf20Sopenharmony_ci if (mpin[i].pin_state == SKL_PIN_UNBIND) 9638c2ecf20Sopenharmony_ci continue; 9648c2ecf20Sopenharmony_ci found = true; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (!found) 9698c2ecf20Sopenharmony_ci mcfg->m_state = SKL_MODULE_INIT_DONE; 9708c2ecf20Sopenharmony_ci return; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/* 9748c2ecf20Sopenharmony_ci * A module needs to be instanataited in DSP. A mdoule is present in a 9758c2ecf20Sopenharmony_ci * collection of module referred as a PIPE. 9768c2ecf20Sopenharmony_ci * We first calculate the module format, based on module type and then 9778c2ecf20Sopenharmony_ci * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ciint skl_init_module(struct skl_dev *skl, 9808c2ecf20Sopenharmony_ci struct skl_module_cfg *mconfig) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci u16 module_config_size = 0; 9838c2ecf20Sopenharmony_ci void *param_data = NULL; 9848c2ecf20Sopenharmony_ci int ret; 9858c2ecf20Sopenharmony_ci struct skl_ipc_init_instance_msg msg; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, 9888c2ecf20Sopenharmony_ci mconfig->id.module_id, mconfig->id.pvt_id); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (mconfig->pipe->state != SKL_PIPE_CREATED) { 9918c2ecf20Sopenharmony_ci dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", 9928c2ecf20Sopenharmony_ci mconfig->pipe->state, mconfig->pipe->ppl_id); 9938c2ecf20Sopenharmony_ci return -EIO; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ret = skl_set_module_format(skl, mconfig, 9978c2ecf20Sopenharmony_ci &module_config_size, ¶m_data); 9988c2ecf20Sopenharmony_ci if (ret < 0) { 9998c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); 10008c2ecf20Sopenharmony_ci return ret; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci msg.module_id = mconfig->id.module_id; 10048c2ecf20Sopenharmony_ci msg.instance_id = mconfig->id.pvt_id; 10058c2ecf20Sopenharmony_ci msg.ppl_instance_id = mconfig->pipe->ppl_id; 10068c2ecf20Sopenharmony_ci msg.param_data_size = module_config_size; 10078c2ecf20Sopenharmony_ci msg.core_id = mconfig->core_id; 10088c2ecf20Sopenharmony_ci msg.domain = mconfig->domain; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); 10118c2ecf20Sopenharmony_ci if (ret < 0) { 10128c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); 10138c2ecf20Sopenharmony_ci kfree(param_data); 10148c2ecf20Sopenharmony_ci return ret; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci mconfig->m_state = SKL_MODULE_INIT_DONE; 10178c2ecf20Sopenharmony_ci kfree(param_data); 10188c2ecf20Sopenharmony_ci return ret; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg 10228c2ecf20Sopenharmony_ci *src_module, struct skl_module_cfg *dst_module) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", 10258c2ecf20Sopenharmony_ci __func__, src_module->id.module_id, src_module->id.pvt_id); 10268c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, 10278c2ecf20Sopenharmony_ci dst_module->id.module_id, dst_module->id.pvt_id); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", 10308c2ecf20Sopenharmony_ci src_module->m_state, dst_module->m_state); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/* 10348c2ecf20Sopenharmony_ci * On module freeup, we need to unbind the module with modules 10358c2ecf20Sopenharmony_ci * it is already bind. 10368c2ecf20Sopenharmony_ci * Find the pin allocated and unbind then using bind_unbind IPC 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ciint skl_unbind_modules(struct skl_dev *skl, 10398c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mcfg, 10408c2ecf20Sopenharmony_ci struct skl_module_cfg *dst_mcfg) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci int ret; 10438c2ecf20Sopenharmony_ci struct skl_ipc_bind_unbind_msg msg; 10448c2ecf20Sopenharmony_ci struct skl_module_inst_id src_id = src_mcfg->id; 10458c2ecf20Sopenharmony_ci struct skl_module_inst_id dst_id = dst_mcfg->id; 10468c2ecf20Sopenharmony_ci int in_max = dst_mcfg->module->max_input_pins; 10478c2ecf20Sopenharmony_ci int out_max = src_mcfg->module->max_output_pins; 10488c2ecf20Sopenharmony_ci int src_index, dst_index, src_pin_state, dst_pin_state; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci skl_dump_bind_info(skl, src_mcfg, dst_mcfg); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* get src queue index */ 10538c2ecf20Sopenharmony_ci src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); 10548c2ecf20Sopenharmony_ci if (src_index < 0) 10558c2ecf20Sopenharmony_ci return 0; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci msg.src_queue = src_index; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* get dst queue index */ 10608c2ecf20Sopenharmony_ci dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); 10618c2ecf20Sopenharmony_ci if (dst_index < 0) 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci msg.dst_queue = dst_index; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; 10678c2ecf20Sopenharmony_ci dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (src_pin_state != SKL_PIN_BIND_DONE || 10708c2ecf20Sopenharmony_ci dst_pin_state != SKL_PIN_BIND_DONE) 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci msg.module_id = src_mcfg->id.module_id; 10748c2ecf20Sopenharmony_ci msg.instance_id = src_mcfg->id.pvt_id; 10758c2ecf20Sopenharmony_ci msg.dst_module_id = dst_mcfg->id.module_id; 10768c2ecf20Sopenharmony_ci msg.dst_instance_id = dst_mcfg->id.pvt_id; 10778c2ecf20Sopenharmony_ci msg.bind = false; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci ret = skl_ipc_bind_unbind(&skl->ipc, &msg); 10808c2ecf20Sopenharmony_ci if (!ret) { 10818c2ecf20Sopenharmony_ci /* free queue only if unbind is success */ 10828c2ecf20Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 10838c2ecf20Sopenharmony_ci skl_free_queue(dst_mcfg->m_in_pin, dst_index); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* 10868c2ecf20Sopenharmony_ci * check only if src module bind state, bind is 10878c2ecf20Sopenharmony_ci * always from src -> sink 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ci skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return ret; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void fill_pin_params(struct skl_audio_data_format *pin_fmt, 10968c2ecf20Sopenharmony_ci struct skl_module_fmt *format) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci pin_fmt->number_of_channels = format->channels; 10998c2ecf20Sopenharmony_ci pin_fmt->s_freq = format->s_freq; 11008c2ecf20Sopenharmony_ci pin_fmt->bit_depth = format->bit_depth; 11018c2ecf20Sopenharmony_ci pin_fmt->valid_bit_depth = format->valid_bit_depth; 11028c2ecf20Sopenharmony_ci pin_fmt->ch_cfg = format->ch_cfg; 11038c2ecf20Sopenharmony_ci pin_fmt->sample_type = format->sample_type; 11048c2ecf20Sopenharmony_ci pin_fmt->channel_map = format->ch_map; 11058c2ecf20Sopenharmony_ci pin_fmt->interleaving = format->interleaving_style; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci#define CPR_SINK_FMT_PARAM_ID 2 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci/* 11118c2ecf20Sopenharmony_ci * Once a module is instantiated it need to be 'bind' with other modules in 11128c2ecf20Sopenharmony_ci * the pipeline. For binding we need to find the module pins which are bind 11138c2ecf20Sopenharmony_ci * together 11148c2ecf20Sopenharmony_ci * This function finds the pins and then sends bund_unbind IPC message to 11158c2ecf20Sopenharmony_ci * DSP using IPC helper 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ciint skl_bind_modules(struct skl_dev *skl, 11188c2ecf20Sopenharmony_ci struct skl_module_cfg *src_mcfg, 11198c2ecf20Sopenharmony_ci struct skl_module_cfg *dst_mcfg) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci int ret = 0; 11228c2ecf20Sopenharmony_ci struct skl_ipc_bind_unbind_msg msg; 11238c2ecf20Sopenharmony_ci int in_max = dst_mcfg->module->max_input_pins; 11248c2ecf20Sopenharmony_ci int out_max = src_mcfg->module->max_output_pins; 11258c2ecf20Sopenharmony_ci int src_index, dst_index; 11268c2ecf20Sopenharmony_ci struct skl_module_fmt *format; 11278c2ecf20Sopenharmony_ci struct skl_cpr_pin_fmt pin_fmt; 11288c2ecf20Sopenharmony_ci struct skl_module *module; 11298c2ecf20Sopenharmony_ci struct skl_module_iface *fmt; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci skl_dump_bind_info(skl, src_mcfg, dst_mcfg); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || 11348c2ecf20Sopenharmony_ci dst_mcfg->m_state < SKL_MODULE_INIT_DONE) 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); 11388c2ecf20Sopenharmony_ci if (src_index < 0) 11398c2ecf20Sopenharmony_ci return -EINVAL; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci msg.src_queue = src_index; 11428c2ecf20Sopenharmony_ci dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); 11438c2ecf20Sopenharmony_ci if (dst_index < 0) { 11448c2ecf20Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 11458c2ecf20Sopenharmony_ci return -EINVAL; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* 11498c2ecf20Sopenharmony_ci * Copier module requires the separate large_config_set_ipc to 11508c2ecf20Sopenharmony_ci * configure the pins other than 0 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) { 11538c2ecf20Sopenharmony_ci pin_fmt.sink_id = src_index; 11548c2ecf20Sopenharmony_ci module = src_mcfg->module; 11558c2ecf20Sopenharmony_ci fmt = &module->formats[src_mcfg->fmt_idx]; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* Input fmt is same as that of src module input cfg */ 11588c2ecf20Sopenharmony_ci format = &fmt->inputs[0].fmt; 11598c2ecf20Sopenharmony_ci fill_pin_params(&(pin_fmt.src_fmt), format); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci format = &fmt->outputs[src_index].fmt; 11628c2ecf20Sopenharmony_ci fill_pin_params(&(pin_fmt.dst_fmt), format); 11638c2ecf20Sopenharmony_ci ret = skl_set_module_params(skl, (void *)&pin_fmt, 11648c2ecf20Sopenharmony_ci sizeof(struct skl_cpr_pin_fmt), 11658c2ecf20Sopenharmony_ci CPR_SINK_FMT_PARAM_ID, src_mcfg); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (ret < 0) 11688c2ecf20Sopenharmony_ci goto out; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci msg.dst_queue = dst_index; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", 11748c2ecf20Sopenharmony_ci msg.src_queue, msg.dst_queue); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci msg.module_id = src_mcfg->id.module_id; 11778c2ecf20Sopenharmony_ci msg.instance_id = src_mcfg->id.pvt_id; 11788c2ecf20Sopenharmony_ci msg.dst_module_id = dst_mcfg->id.module_id; 11798c2ecf20Sopenharmony_ci msg.dst_instance_id = dst_mcfg->id.pvt_id; 11808c2ecf20Sopenharmony_ci msg.bind = true; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci ret = skl_ipc_bind_unbind(&skl->ipc, &msg); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (!ret) { 11858c2ecf20Sopenharmony_ci src_mcfg->m_state = SKL_MODULE_BIND_DONE; 11868c2ecf20Sopenharmony_ci src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; 11878c2ecf20Sopenharmony_ci dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; 11888c2ecf20Sopenharmony_ci return ret; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ciout: 11918c2ecf20Sopenharmony_ci /* error case , if IPC fails, clear the queue index */ 11928c2ecf20Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 11938c2ecf20Sopenharmony_ci skl_free_queue(dst_mcfg->m_in_pin, dst_index); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return ret; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, 11998c2ecf20Sopenharmony_ci enum skl_ipc_pipeline_state state) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci/* 12078c2ecf20Sopenharmony_ci * A pipeline is a collection of modules. Before a module in instantiated a 12088c2ecf20Sopenharmony_ci * pipeline needs to be created for it. 12098c2ecf20Sopenharmony_ci * This function creates pipeline, by sending create pipeline IPC messages 12108c2ecf20Sopenharmony_ci * to FW 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ciint skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci int ret; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, 12198c2ecf20Sopenharmony_ci pipe->pipe_priority, pipe->ppl_id, 12208c2ecf20Sopenharmony_ci pipe->lp_mode); 12218c2ecf20Sopenharmony_ci if (ret < 0) { 12228c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to create pipeline\n"); 12238c2ecf20Sopenharmony_ci return ret; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_CREATED; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return 0; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/* 12328c2ecf20Sopenharmony_ci * A pipeline needs to be deleted on cleanup. If a pipeline is running, 12338c2ecf20Sopenharmony_ci * then pause it first. Before actual deletion, pipeline should enter 12348c2ecf20Sopenharmony_ci * reset state. Finish the procedure by sending delete pipeline IPC. 12358c2ecf20Sopenharmony_ci * DSP will stop the DMA engines and release resources 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_ciint skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci int ret; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci /* If pipe was not created in FW, do not try to delete it */ 12448c2ecf20Sopenharmony_ci if (pipe->state < SKL_PIPE_CREATED) 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* If pipe is started, do stop the pipe in FW. */ 12488c2ecf20Sopenharmony_ci if (pipe->state >= SKL_PIPE_STARTED) { 12498c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 12508c2ecf20Sopenharmony_ci if (ret < 0) { 12518c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to stop pipeline\n"); 12528c2ecf20Sopenharmony_ci return ret; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* reset pipe state before deletion */ 12598c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RESET); 12608c2ecf20Sopenharmony_ci if (ret < 0) { 12618c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); 12628c2ecf20Sopenharmony_ci return ret; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_RESET; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); 12688c2ecf20Sopenharmony_ci if (ret < 0) { 12698c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to delete pipeline\n"); 12708c2ecf20Sopenharmony_ci return ret; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_INVALID; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return ret; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci/* 12798c2ecf20Sopenharmony_ci * A pipeline is also a scheduling entity in DSP which can be run, stopped 12808c2ecf20Sopenharmony_ci * For processing data the pipe need to be run by sending IPC set pipe state 12818c2ecf20Sopenharmony_ci * to DSP 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_ciint skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci int ret; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 12908c2ecf20Sopenharmony_ci if (pipe->state < SKL_PIPE_CREATED) 12918c2ecf20Sopenharmony_ci return 0; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* Pipe has to be paused before it is started */ 12948c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 12958c2ecf20Sopenharmony_ci if (ret < 0) { 12968c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to pause pipe\n"); 12978c2ecf20Sopenharmony_ci return ret; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); 13038c2ecf20Sopenharmony_ci if (ret < 0) { 13048c2ecf20Sopenharmony_ci dev_err(skl->dev, "Failed to start pipe\n"); 13058c2ecf20Sopenharmony_ci return ret; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_STARTED; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci return 0; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci/* 13148c2ecf20Sopenharmony_ci * Stop the pipeline by sending set pipe state IPC 13158c2ecf20Sopenharmony_ci * DSP doesnt implement stop so we always send pause message 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ciint skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci int ret; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 13248c2ecf20Sopenharmony_ci if (pipe->state < SKL_PIPE_PAUSED) 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 13288c2ecf20Sopenharmony_ci if (ret < 0) { 13298c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Failed to stop pipe\n"); 13308c2ecf20Sopenharmony_ci return ret; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return 0; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci/* 13398c2ecf20Sopenharmony_ci * Reset the pipeline by sending set pipe state IPC this will reset the DMA 13408c2ecf20Sopenharmony_ci * from the DSP side 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ciint skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci int ret; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 13478c2ecf20Sopenharmony_ci if (pipe->state < SKL_PIPE_PAUSED) 13488c2ecf20Sopenharmony_ci return 0; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RESET); 13518c2ecf20Sopenharmony_ci if (ret < 0) { 13528c2ecf20Sopenharmony_ci dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); 13538c2ecf20Sopenharmony_ci return ret; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci pipe->state = SKL_PIPE_RESET; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci/* Algo parameter set helper function */ 13628c2ecf20Sopenharmony_ciint skl_set_module_params(struct skl_dev *skl, u32 *params, int size, 13638c2ecf20Sopenharmony_ci u32 param_id, struct skl_module_cfg *mcfg) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct skl_ipc_large_config_msg msg; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci msg.module_id = mcfg->id.module_id; 13688c2ecf20Sopenharmony_ci msg.instance_id = mcfg->id.pvt_id; 13698c2ecf20Sopenharmony_ci msg.param_data_size = size; 13708c2ecf20Sopenharmony_ci msg.large_param_id = param_id; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci return skl_ipc_set_large_config(&skl->ipc, &msg, params); 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ciint skl_get_module_params(struct skl_dev *skl, u32 *params, int size, 13768c2ecf20Sopenharmony_ci u32 param_id, struct skl_module_cfg *mcfg) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct skl_ipc_large_config_msg msg; 13798c2ecf20Sopenharmony_ci size_t bytes = size; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci msg.module_id = mcfg->id.module_id; 13828c2ecf20Sopenharmony_ci msg.instance_id = mcfg->id.pvt_id; 13838c2ecf20Sopenharmony_ci msg.param_data_size = size; 13848c2ecf20Sopenharmony_ci msg.large_param_id = param_id; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); 13878c2ecf20Sopenharmony_ci} 1388