162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * skl-message.c - HDA DSP interface for FW registration, Pipe and Module 462306a36Sopenharmony_ci * configurations 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2015 Intel Corp 762306a36Sopenharmony_ci * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> 862306a36Sopenharmony_ci * Jeeja KP <jeeja.kp@intel.com> 962306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <sound/core.h> 1562306a36Sopenharmony_ci#include <sound/pcm.h> 1662306a36Sopenharmony_ci#include <uapi/sound/skl-tplg-interface.h> 1762306a36Sopenharmony_ci#include "skl-sst-dsp.h" 1862306a36Sopenharmony_ci#include "cnl-sst-dsp.h" 1962306a36Sopenharmony_ci#include "skl-sst-ipc.h" 2062306a36Sopenharmony_ci#include "skl.h" 2162306a36Sopenharmony_ci#include "../common/sst-dsp.h" 2262306a36Sopenharmony_ci#include "../common/sst-dsp-priv.h" 2362306a36Sopenharmony_ci#include "skl-topology.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int skl_alloc_dma_buf(struct device *dev, 2662306a36Sopenharmony_ci struct snd_dma_buffer *dmab, size_t size) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci snd_dma_free_pages(dmab); 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define SKL_ASTATE_PARAM_ID 4 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_civoid skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct skl_ipc_large_config_msg msg = {0}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci msg.large_param_id = SKL_ASTATE_PARAM_ID; 4462306a36Sopenharmony_ci msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + 4562306a36Sopenharmony_ci sizeof(cnt)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci skl_ipc_set_large_config(&skl->ipc, &msg, data); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int skl_dsp_setup_spib(struct device *dev, unsigned int size, 5162306a36Sopenharmony_ci int stream_tag, int enable) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 5462306a36Sopenharmony_ci struct hdac_stream *stream = snd_hdac_get_stream(bus, 5562306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!stream) 5862306a36Sopenharmony_ci return -EINVAL; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* enable/disable SPIB for this hdac stream */ 6162306a36Sopenharmony_ci snd_hdac_stream_spbcap_enable(bus, enable, stream->index); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* set the spib value */ 6462306a36Sopenharmony_ci snd_hdac_stream_set_spib(bus, stream, size); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int skl_dsp_prepare(struct device *dev, unsigned int format, 7062306a36Sopenharmony_ci unsigned int size, struct snd_dma_buffer *dmab) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 7362306a36Sopenharmony_ci struct hdac_ext_stream *estream; 7462306a36Sopenharmony_ci struct hdac_stream *stream; 7562306a36Sopenharmony_ci struct snd_pcm_substream substream; 7662306a36Sopenharmony_ci int ret; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!bus) 7962306a36Sopenharmony_ci return -ENODEV; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci memset(&substream, 0, sizeof(substream)); 8262306a36Sopenharmony_ci substream.stream = SNDRV_PCM_STREAM_PLAYBACK; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci estream = snd_hdac_ext_stream_assign(bus, &substream, 8562306a36Sopenharmony_ci HDAC_EXT_STREAM_TYPE_HOST); 8662306a36Sopenharmony_ci if (!estream) 8762306a36Sopenharmony_ci return -ENODEV; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci stream = hdac_stream(estream); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* assign decouple host dma channel */ 9262306a36Sopenharmony_ci ret = snd_hdac_dsp_prepare(stream, format, size, dmab); 9362306a36Sopenharmony_ci if (ret < 0) 9462306a36Sopenharmony_ci return ret; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci skl_dsp_setup_spib(dev, size, stream->stream_tag, true); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return stream->stream_tag; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int skl_dsp_trigger(struct device *dev, bool start, int stream_tag) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 10462306a36Sopenharmony_ci struct hdac_stream *stream; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!bus) 10762306a36Sopenharmony_ci return -ENODEV; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci stream = snd_hdac_get_stream(bus, 11062306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 11162306a36Sopenharmony_ci if (!stream) 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci snd_hdac_dsp_trigger(stream, start); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int skl_dsp_cleanup(struct device *dev, 12062306a36Sopenharmony_ci struct snd_dma_buffer *dmab, int stream_tag) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct hdac_bus *bus = dev_get_drvdata(dev); 12362306a36Sopenharmony_ci struct hdac_stream *stream; 12462306a36Sopenharmony_ci struct hdac_ext_stream *estream; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!bus) 12762306a36Sopenharmony_ci return -ENODEV; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci stream = snd_hdac_get_stream(bus, 13062306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK, stream_tag); 13162306a36Sopenharmony_ci if (!stream) 13262306a36Sopenharmony_ci return -EINVAL; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci estream = stream_to_hdac_ext_stream(stream); 13562306a36Sopenharmony_ci skl_dsp_setup_spib(dev, 0, stream_tag, false); 13662306a36Sopenharmony_ci snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci snd_hdac_dsp_cleanup(stream, dmab); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic struct skl_dsp_loader_ops skl_get_loader_ops(void) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci loader_ops.alloc_dma_buf = skl_alloc_dma_buf; 15062306a36Sopenharmony_ci loader_ops.free_dma_buf = skl_free_dma_buf; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return loader_ops; 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic struct skl_dsp_loader_ops bxt_get_loader_ops(void) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci memset(&loader_ops, 0, sizeof(loader_ops)); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci loader_ops.alloc_dma_buf = skl_alloc_dma_buf; 16262306a36Sopenharmony_ci loader_ops.free_dma_buf = skl_free_dma_buf; 16362306a36Sopenharmony_ci loader_ops.prepare = skl_dsp_prepare; 16462306a36Sopenharmony_ci loader_ops.trigger = skl_dsp_trigger; 16562306a36Sopenharmony_ci loader_ops.cleanup = skl_dsp_cleanup; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return loader_ops; 16862306a36Sopenharmony_ci}; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic const struct skl_dsp_ops dsp_ops[] = { 17162306a36Sopenharmony_ci { 17262306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, 17362306a36Sopenharmony_ci .num_cores = 2, 17462306a36Sopenharmony_ci .loader_ops = skl_get_loader_ops, 17562306a36Sopenharmony_ci .init = skl_sst_dsp_init, 17662306a36Sopenharmony_ci .init_fw = skl_sst_init_fw, 17762306a36Sopenharmony_ci .cleanup = skl_sst_dsp_cleanup 17862306a36Sopenharmony_ci }, 17962306a36Sopenharmony_ci { 18062306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, 18162306a36Sopenharmony_ci .num_cores = 2, 18262306a36Sopenharmony_ci .loader_ops = skl_get_loader_ops, 18362306a36Sopenharmony_ci .init = skl_sst_dsp_init, 18462306a36Sopenharmony_ci .init_fw = skl_sst_init_fw, 18562306a36Sopenharmony_ci .cleanup = skl_sst_dsp_cleanup 18662306a36Sopenharmony_ci }, 18762306a36Sopenharmony_ci { 18862306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_APL, 18962306a36Sopenharmony_ci .num_cores = 2, 19062306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 19162306a36Sopenharmony_ci .init = bxt_sst_dsp_init, 19262306a36Sopenharmony_ci .init_fw = bxt_sst_init_fw, 19362306a36Sopenharmony_ci .cleanup = bxt_sst_dsp_cleanup 19462306a36Sopenharmony_ci }, 19562306a36Sopenharmony_ci { 19662306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_GML, 19762306a36Sopenharmony_ci .num_cores = 2, 19862306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 19962306a36Sopenharmony_ci .init = bxt_sst_dsp_init, 20062306a36Sopenharmony_ci .init_fw = bxt_sst_init_fw, 20162306a36Sopenharmony_ci .cleanup = bxt_sst_dsp_cleanup 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, 20562306a36Sopenharmony_ci .num_cores = 4, 20662306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 20762306a36Sopenharmony_ci .init = cnl_sst_dsp_init, 20862306a36Sopenharmony_ci .init_fw = cnl_sst_init_fw, 20962306a36Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 21062306a36Sopenharmony_ci }, 21162306a36Sopenharmony_ci { 21262306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H, 21362306a36Sopenharmony_ci .num_cores = 4, 21462306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 21562306a36Sopenharmony_ci .init = cnl_sst_dsp_init, 21662306a36Sopenharmony_ci .init_fw = cnl_sst_init_fw, 21762306a36Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 21862306a36Sopenharmony_ci }, 21962306a36Sopenharmony_ci { 22062306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP, 22162306a36Sopenharmony_ci .num_cores = 4, 22262306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 22362306a36Sopenharmony_ci .init = cnl_sst_dsp_init, 22462306a36Sopenharmony_ci .init_fw = cnl_sst_init_fw, 22562306a36Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 22662306a36Sopenharmony_ci }, 22762306a36Sopenharmony_ci { 22862306a36Sopenharmony_ci .id = PCI_DEVICE_ID_INTEL_HDA_CML_H, 22962306a36Sopenharmony_ci .num_cores = 4, 23062306a36Sopenharmony_ci .loader_ops = bxt_get_loader_ops, 23162306a36Sopenharmony_ci .init = cnl_sst_dsp_init, 23262306a36Sopenharmony_ci .init_fw = cnl_sst_init_fw, 23362306a36Sopenharmony_ci .cleanup = cnl_sst_dsp_cleanup 23462306a36Sopenharmony_ci }, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciconst struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int i; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { 24262306a36Sopenharmony_ci if (dsp_ops[i].id == pci_id) 24362306a36Sopenharmony_ci return &dsp_ops[i]; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return NULL; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ciint skl_init_dsp(struct skl_dev *skl) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci void __iomem *mmio_base; 25262306a36Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 25362306a36Sopenharmony_ci struct skl_dsp_loader_ops loader_ops; 25462306a36Sopenharmony_ci int irq = bus->irq; 25562306a36Sopenharmony_ci const struct skl_dsp_ops *ops; 25662306a36Sopenharmony_ci struct skl_dsp_cores *cores; 25762306a36Sopenharmony_ci int ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* enable ppcap interrupt */ 26062306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, true); 26162306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, true); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* read the BAR of the ADSP MMIO */ 26462306a36Sopenharmony_ci mmio_base = pci_ioremap_bar(skl->pci, 4); 26562306a36Sopenharmony_ci if (mmio_base == NULL) { 26662306a36Sopenharmony_ci dev_err(bus->dev, "ioremap error\n"); 26762306a36Sopenharmony_ci return -ENXIO; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ops = skl_get_dsp_ops(skl->pci->device); 27162306a36Sopenharmony_ci if (!ops) { 27262306a36Sopenharmony_ci ret = -EIO; 27362306a36Sopenharmony_ci goto unmap_mmio; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci loader_ops = ops->loader_ops(); 27762306a36Sopenharmony_ci ret = ops->init(bus->dev, mmio_base, irq, 27862306a36Sopenharmony_ci skl->fw_name, loader_ops, 27962306a36Sopenharmony_ci &skl); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (ret < 0) 28262306a36Sopenharmony_ci goto unmap_mmio; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci skl->dsp_ops = ops; 28562306a36Sopenharmony_ci cores = &skl->cores; 28662306a36Sopenharmony_ci cores->count = ops->num_cores; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); 28962306a36Sopenharmony_ci if (!cores->state) { 29062306a36Sopenharmony_ci ret = -ENOMEM; 29162306a36Sopenharmony_ci goto unmap_mmio; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count), 29562306a36Sopenharmony_ci GFP_KERNEL); 29662306a36Sopenharmony_ci if (!cores->usage_count) { 29762306a36Sopenharmony_ci ret = -ENOMEM; 29862306a36Sopenharmony_ci goto free_core_state; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci dev_dbg(bus->dev, "dsp registration status=%d\n", ret); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cifree_core_state: 30662306a36Sopenharmony_ci kfree(cores->state); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciunmap_mmio: 30962306a36Sopenharmony_ci iounmap(mmio_base); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return ret; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciint skl_free_dsp(struct skl_dev *skl) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* disable ppcap interrupt */ 31962306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, false); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci skl->dsp_ops->cleanup(bus->dev, skl); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci kfree(skl->cores.state); 32462306a36Sopenharmony_ci kfree(skl->cores.usage_count); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (skl->dsp->addr.lpe) 32762306a36Sopenharmony_ci iounmap(skl->dsp->addr.lpe); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* 33362306a36Sopenharmony_ci * In the case of "suspend_active" i.e, the Audio IP being active 33462306a36Sopenharmony_ci * during system suspend, immediately excecute any pending D0i3 work 33562306a36Sopenharmony_ci * before suspending. This is needed for the IP to work in low power 33662306a36Sopenharmony_ci * mode during system suspend. In the case of normal suspend, cancel 33762306a36Sopenharmony_ci * any pending D0i3 work. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ciint skl_suspend_late_dsp(struct skl_dev *skl) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct delayed_work *dwork; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!skl) 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci dwork = &skl->d0i3.work; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (dwork->work.func) { 34962306a36Sopenharmony_ci if (skl->supend_active) 35062306a36Sopenharmony_ci flush_delayed_work(dwork); 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci cancel_delayed_work_sync(dwork); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ciint skl_suspend_dsp(struct skl_dev *skl) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 36162306a36Sopenharmony_ci int ret; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* if ppcap is not supported return 0 */ 36462306a36Sopenharmony_ci if (!bus->ppcap) 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci ret = skl_dsp_sleep(skl->dsp); 36862306a36Sopenharmony_ci if (ret < 0) 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* disable ppcap interrupt */ 37262306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, false); 37362306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, false); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciint skl_resume_dsp(struct skl_dev *skl) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* if ppcap is not supported return 0 */ 38462306a36Sopenharmony_ci if (!bus->ppcap) 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* enable ppcap interrupt */ 38862306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_enable(bus, true); 38962306a36Sopenharmony_ci snd_hdac_ext_bus_ppcap_int_enable(bus, true); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* check if DSP 1st boot is done */ 39262306a36Sopenharmony_ci if (skl->is_first_boot) 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* 39662306a36Sopenharmony_ci * Disable dynamic clock and power gating during firmware 39762306a36Sopenharmony_ci * and library download 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci skl->enable_miscbdcge(skl->dev, false); 40062306a36Sopenharmony_ci skl->clock_power_gating(skl->dev, false); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci ret = skl_dsp_wake(skl->dsp); 40362306a36Sopenharmony_ci skl->enable_miscbdcge(skl->dev, true); 40462306a36Sopenharmony_ci skl->clock_power_gating(skl->dev, true); 40562306a36Sopenharmony_ci if (ret < 0) 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (skl->cfg.astate_cfg != NULL) { 40962306a36Sopenharmony_ci skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, 41062306a36Sopenharmony_ci skl->cfg.astate_cfg); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cienum skl_bitdepth skl_get_bit_depth(int params) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci switch (params) { 41862306a36Sopenharmony_ci case 8: 41962306a36Sopenharmony_ci return SKL_DEPTH_8BIT; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci case 16: 42262306a36Sopenharmony_ci return SKL_DEPTH_16BIT; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci case 24: 42562306a36Sopenharmony_ci return SKL_DEPTH_24BIT; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci case 32: 42862306a36Sopenharmony_ci return SKL_DEPTH_32BIT; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci default: 43162306a36Sopenharmony_ci return SKL_DEPTH_INVALID; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* 43762306a36Sopenharmony_ci * Each module in DSP expects a base module configuration, which consists of 43862306a36Sopenharmony_ci * PCM format information, which we calculate in driver and resource values 43962306a36Sopenharmony_ci * which are read from widget information passed through topology binary 44062306a36Sopenharmony_ci * This is send when we create a module with INIT_INSTANCE IPC msg 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_cistatic void skl_set_base_module_format(struct skl_dev *skl, 44362306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 44462306a36Sopenharmony_ci struct skl_base_cfg *base_cfg) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 44762306a36Sopenharmony_ci struct skl_module_res *res = &module->resources[mconfig->res_idx]; 44862306a36Sopenharmony_ci struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; 44962306a36Sopenharmony_ci struct skl_module_fmt *format = &fmt->inputs[0].fmt; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci base_cfg->audio_fmt.number_of_channels = format->channels; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci base_cfg->audio_fmt.s_freq = format->s_freq; 45462306a36Sopenharmony_ci base_cfg->audio_fmt.bit_depth = format->bit_depth; 45562306a36Sopenharmony_ci base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; 45662306a36Sopenharmony_ci base_cfg->audio_fmt.ch_cfg = format->ch_cfg; 45762306a36Sopenharmony_ci base_cfg->audio_fmt.sample_type = format->sample_type; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", 46062306a36Sopenharmony_ci format->bit_depth, format->valid_bit_depth, 46162306a36Sopenharmony_ci format->ch_cfg); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci base_cfg->audio_fmt.channel_map = format->ch_map; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci base_cfg->audio_fmt.interleaving = format->interleaving_style; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci base_cfg->cpc = res->cpc; 46862306a36Sopenharmony_ci base_cfg->ibs = res->ibs; 46962306a36Sopenharmony_ci base_cfg->obs = res->obs; 47062306a36Sopenharmony_ci base_cfg->is_pages = res->is_pages; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void fill_pin_params(struct skl_audio_data_format *pin_fmt, 47462306a36Sopenharmony_ci struct skl_module_fmt *format) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci pin_fmt->number_of_channels = format->channels; 47762306a36Sopenharmony_ci pin_fmt->s_freq = format->s_freq; 47862306a36Sopenharmony_ci pin_fmt->bit_depth = format->bit_depth; 47962306a36Sopenharmony_ci pin_fmt->valid_bit_depth = format->valid_bit_depth; 48062306a36Sopenharmony_ci pin_fmt->ch_cfg = format->ch_cfg; 48162306a36Sopenharmony_ci pin_fmt->sample_type = format->sample_type; 48262306a36Sopenharmony_ci pin_fmt->channel_map = format->ch_map; 48362306a36Sopenharmony_ci pin_fmt->interleaving = format->interleaving_style; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* 48762306a36Sopenharmony_ci * Any module configuration begins with a base module configuration but 48862306a36Sopenharmony_ci * can be followed by a generic extension containing audio format for all 48962306a36Sopenharmony_ci * module's pins that are in use. 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_cistatic void skl_set_base_ext_module_format(struct skl_dev *skl, 49262306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 49362306a36Sopenharmony_ci struct skl_base_cfg_ext *base_cfg_ext) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 49662306a36Sopenharmony_ci struct skl_module_pin_resources *pin_res; 49762306a36Sopenharmony_ci struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; 49862306a36Sopenharmony_ci struct skl_module_res *res = &module->resources[mconfig->res_idx]; 49962306a36Sopenharmony_ci struct skl_module_fmt *format; 50062306a36Sopenharmony_ci struct skl_pin_format *pin_fmt; 50162306a36Sopenharmony_ci char *params; 50262306a36Sopenharmony_ci int i; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci base_cfg_ext->nr_input_pins = res->nr_input_pins; 50562306a36Sopenharmony_ci base_cfg_ext->nr_output_pins = res->nr_output_pins; 50662306a36Sopenharmony_ci base_cfg_ext->priv_param_length = 50762306a36Sopenharmony_ci mconfig->formats_config[SKL_PARAM_INIT].caps_size; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i < res->nr_input_pins; i++) { 51062306a36Sopenharmony_ci pin_res = &res->input[i]; 51162306a36Sopenharmony_ci pin_fmt = &base_cfg_ext->pins_fmt[i]; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci pin_fmt->pin_idx = pin_res->pin_index; 51462306a36Sopenharmony_ci pin_fmt->buf_size = pin_res->buf_size; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci format = &fmt->inputs[pin_res->pin_index].fmt; 51762306a36Sopenharmony_ci fill_pin_params(&pin_fmt->audio_fmt, format); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci for (i = 0; i < res->nr_output_pins; i++) { 52162306a36Sopenharmony_ci pin_res = &res->output[i]; 52262306a36Sopenharmony_ci pin_fmt = &base_cfg_ext->pins_fmt[res->nr_input_pins + i]; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci pin_fmt->pin_idx = pin_res->pin_index; 52562306a36Sopenharmony_ci pin_fmt->buf_size = pin_res->buf_size; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci format = &fmt->outputs[pin_res->pin_index].fmt; 52862306a36Sopenharmony_ci fill_pin_params(&pin_fmt->audio_fmt, format); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (!base_cfg_ext->priv_param_length) 53262306a36Sopenharmony_ci return; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci params = (char *)base_cfg_ext + sizeof(struct skl_base_cfg_ext); 53562306a36Sopenharmony_ci params += (base_cfg_ext->nr_input_pins + base_cfg_ext->nr_output_pins) * 53662306a36Sopenharmony_ci sizeof(struct skl_pin_format); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci memcpy(params, mconfig->formats_config[SKL_PARAM_INIT].caps, 53962306a36Sopenharmony_ci mconfig->formats_config[SKL_PARAM_INIT].caps_size); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Copies copier capabilities into copier module and updates copier module 54462306a36Sopenharmony_ci * config size. 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_cistatic void skl_copy_copier_caps(struct skl_module_cfg *mconfig, 54762306a36Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci if (mconfig->formats_config[SKL_PARAM_INIT].caps_size == 0) 55062306a36Sopenharmony_ci return; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci memcpy(&cpr_mconfig->gtw_cfg.config_data, 55362306a36Sopenharmony_ci mconfig->formats_config[SKL_PARAM_INIT].caps, 55462306a36Sopenharmony_ci mconfig->formats_config[SKL_PARAM_INIT].caps_size); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.config_length = 55762306a36Sopenharmony_ci (mconfig->formats_config[SKL_PARAM_INIT].caps_size) / 4; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF 56162306a36Sopenharmony_ci/* 56262306a36Sopenharmony_ci * Calculate the gatewat settings required for copier module, type of 56362306a36Sopenharmony_ci * gateway and index of gateway to use 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic u32 skl_get_node_id(struct skl_dev *skl, 56662306a36Sopenharmony_ci struct skl_module_cfg *mconfig) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci union skl_connector_node_id node_id = {0}; 56962306a36Sopenharmony_ci union skl_ssp_dma_node ssp_node = {0}; 57062306a36Sopenharmony_ci struct skl_pipe_params *params = mconfig->pipe->p_params; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci switch (mconfig->dev_type) { 57362306a36Sopenharmony_ci case SKL_DEVICE_BT: 57462306a36Sopenharmony_ci node_id.node.dma_type = 57562306a36Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 57662306a36Sopenharmony_ci SKL_DMA_I2S_LINK_OUTPUT_CLASS : 57762306a36Sopenharmony_ci SKL_DMA_I2S_LINK_INPUT_CLASS; 57862306a36Sopenharmony_ci node_id.node.vindex = params->host_dma_id + 57962306a36Sopenharmony_ci (mconfig->vbus_id << 3); 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci case SKL_DEVICE_I2S: 58362306a36Sopenharmony_ci node_id.node.dma_type = 58462306a36Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 58562306a36Sopenharmony_ci SKL_DMA_I2S_LINK_OUTPUT_CLASS : 58662306a36Sopenharmony_ci SKL_DMA_I2S_LINK_INPUT_CLASS; 58762306a36Sopenharmony_ci ssp_node.dma_node.time_slot_index = mconfig->time_slot; 58862306a36Sopenharmony_ci ssp_node.dma_node.i2s_instance = mconfig->vbus_id; 58962306a36Sopenharmony_ci node_id.node.vindex = ssp_node.val; 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci case SKL_DEVICE_DMIC: 59362306a36Sopenharmony_ci node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS; 59462306a36Sopenharmony_ci node_id.node.vindex = mconfig->vbus_id + 59562306a36Sopenharmony_ci (mconfig->time_slot); 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci case SKL_DEVICE_HDALINK: 59962306a36Sopenharmony_ci node_id.node.dma_type = 60062306a36Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 60162306a36Sopenharmony_ci SKL_DMA_HDA_LINK_OUTPUT_CLASS : 60262306a36Sopenharmony_ci SKL_DMA_HDA_LINK_INPUT_CLASS; 60362306a36Sopenharmony_ci node_id.node.vindex = params->link_dma_id; 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci case SKL_DEVICE_HDAHOST: 60762306a36Sopenharmony_ci node_id.node.dma_type = 60862306a36Sopenharmony_ci (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? 60962306a36Sopenharmony_ci SKL_DMA_HDA_HOST_OUTPUT_CLASS : 61062306a36Sopenharmony_ci SKL_DMA_HDA_HOST_INPUT_CLASS; 61162306a36Sopenharmony_ci node_id.node.vindex = params->host_dma_id; 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci default: 61562306a36Sopenharmony_ci node_id.val = 0xFFFFFFFF; 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return node_id.val; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, 62362306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 62462306a36Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci u32 dma_io_buf; 62762306a36Sopenharmony_ci struct skl_module_res *res; 62862306a36Sopenharmony_ci int res_idx = mconfig->res_idx; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { 63362306a36Sopenharmony_ci cpr_mconfig->cpr_feature_mask = 0; 63462306a36Sopenharmony_ci return; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (skl->nr_modules) { 63862306a36Sopenharmony_ci res = &mconfig->module->resources[mconfig->res_idx]; 63962306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size; 64062306a36Sopenharmony_ci goto skip_buf_size_calc; 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci res = &mconfig->module->resources[res_idx]; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci switch (mconfig->hw_conn_type) { 64662306a36Sopenharmony_ci case SKL_CONN_SOURCE: 64762306a36Sopenharmony_ci if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 64862306a36Sopenharmony_ci dma_io_buf = res->ibs; 64962306a36Sopenharmony_ci else 65062306a36Sopenharmony_ci dma_io_buf = res->obs; 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci case SKL_CONN_SINK: 65462306a36Sopenharmony_ci if (mconfig->dev_type == SKL_DEVICE_HDAHOST) 65562306a36Sopenharmony_ci dma_io_buf = res->obs; 65662306a36Sopenharmony_ci else 65762306a36Sopenharmony_ci dma_io_buf = res->ibs; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci default: 66162306a36Sopenharmony_ci dev_warn(skl->dev, "wrong connection type: %d\n", 66262306a36Sopenharmony_ci mconfig->hw_conn_type); 66362306a36Sopenharmony_ci return; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 66762306a36Sopenharmony_ci mconfig->dma_buffer_size * dma_io_buf; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* fallback to 2ms default value */ 67062306a36Sopenharmony_ci if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { 67162306a36Sopenharmony_ci if (mconfig->hw_conn_type == SKL_CONN_SOURCE) 67262306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs; 67362306a36Sopenharmony_ci else 67462306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ciskip_buf_size_calc: 67862306a36Sopenharmony_ci cpr_mconfig->cpr_feature_mask = 0; 67962306a36Sopenharmony_ci cpr_mconfig->gtw_cfg.config_length = 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci skl_copy_copier_caps(mconfig, cpr_mconfig); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci#define DMA_CONTROL_ID 5 68562306a36Sopenharmony_ci#define DMA_I2S_BLOB_SIZE 21 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ciint skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, 68862306a36Sopenharmony_ci u32 caps_size, u32 node_id) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct skl_dma_control *dma_ctrl; 69162306a36Sopenharmony_ci struct skl_ipc_large_config_msg msg = {0}; 69262306a36Sopenharmony_ci int err = 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * if blob size zero, then return 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci if (caps_size == 0) 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci msg.large_param_id = DMA_CONTROL_ID; 70262306a36Sopenharmony_ci msg.param_data_size = sizeof(struct skl_dma_control) + caps_size; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL); 70562306a36Sopenharmony_ci if (dma_ctrl == NULL) 70662306a36Sopenharmony_ci return -ENOMEM; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci dma_ctrl->node_id = node_id; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * NHLT blob may contain additional configs along with i2s blob. 71262306a36Sopenharmony_ci * firmware expects only the i2s blob size as the config_length. 71362306a36Sopenharmony_ci * So fix to i2s blob size. 71462306a36Sopenharmony_ci * size in dwords. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci dma_ctrl->config_length = DMA_I2S_BLOB_SIZE; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci memcpy(dma_ctrl->config_data, caps, caps_size); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci kfree(dma_ctrl); 72362306a36Sopenharmony_ci return err; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic void skl_setup_out_format(struct skl_dev *skl, 72862306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 72962306a36Sopenharmony_ci struct skl_audio_data_format *out_fmt) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 73262306a36Sopenharmony_ci struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; 73362306a36Sopenharmony_ci struct skl_module_fmt *format = &fmt->outputs[0].fmt; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci out_fmt->number_of_channels = (u8)format->channels; 73662306a36Sopenharmony_ci out_fmt->s_freq = format->s_freq; 73762306a36Sopenharmony_ci out_fmt->bit_depth = format->bit_depth; 73862306a36Sopenharmony_ci out_fmt->valid_bit_depth = format->valid_bit_depth; 73962306a36Sopenharmony_ci out_fmt->ch_cfg = format->ch_cfg; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci out_fmt->channel_map = format->ch_map; 74262306a36Sopenharmony_ci out_fmt->interleaving = format->interleaving_style; 74362306a36Sopenharmony_ci out_fmt->sample_type = format->sample_type; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", 74662306a36Sopenharmony_ci out_fmt->number_of_channels, format->s_freq, format->bit_depth); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci/* 75062306a36Sopenharmony_ci * DSP needs SRC module for frequency conversion, SRC takes base module 75162306a36Sopenharmony_ci * configuration and the target frequency as extra parameter passed as src 75262306a36Sopenharmony_ci * config 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_cistatic void skl_set_src_format(struct skl_dev *skl, 75562306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 75662306a36Sopenharmony_ci struct skl_src_module_cfg *src_mconfig) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 75962306a36Sopenharmony_ci struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; 76062306a36Sopenharmony_ci struct skl_module_fmt *fmt = &iface->outputs[0].fmt; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci skl_set_base_module_format(skl, mconfig, 76362306a36Sopenharmony_ci (struct skl_base_cfg *)src_mconfig); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci src_mconfig->src_cfg = fmt->s_freq; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* 76962306a36Sopenharmony_ci * DSP needs updown module to do channel conversion. updown module take base 77062306a36Sopenharmony_ci * module configuration and channel configuration 77162306a36Sopenharmony_ci * It also take coefficients and now we have defaults applied here 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_cistatic void skl_set_updown_mixer_format(struct skl_dev *skl, 77462306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 77562306a36Sopenharmony_ci struct skl_up_down_mixer_cfg *mixer_mconfig) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 77862306a36Sopenharmony_ci struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; 77962306a36Sopenharmony_ci struct skl_module_fmt *fmt = &iface->outputs[0].fmt; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci skl_set_base_module_format(skl, mconfig, 78262306a36Sopenharmony_ci (struct skl_base_cfg *)mixer_mconfig); 78362306a36Sopenharmony_ci mixer_mconfig->out_ch_cfg = fmt->ch_cfg; 78462306a36Sopenharmony_ci mixer_mconfig->ch_map = fmt->ch_map; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci/* 78862306a36Sopenharmony_ci * 'copier' is DSP internal module which copies data from Host DMA (HDA host 78962306a36Sopenharmony_ci * dma) or link (hda link, SSP, PDM) 79062306a36Sopenharmony_ci * Here we calculate the copier module parameters, like PCM format, output 79162306a36Sopenharmony_ci * format, gateway settings 79262306a36Sopenharmony_ci * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_cistatic void skl_set_copier_format(struct skl_dev *skl, 79562306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 79662306a36Sopenharmony_ci struct skl_cpr_cfg *cpr_mconfig) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; 79962306a36Sopenharmony_ci struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci skl_set_base_module_format(skl, mconfig, base_cfg); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci skl_setup_out_format(skl, mconfig, out_fmt); 80462306a36Sopenharmony_ci skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/* 80862306a36Sopenharmony_ci * Mic select module allows selecting one or many input channels, thus 80962306a36Sopenharmony_ci * acting as a demux. 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * Mic select module take base module configuration and out-format 81262306a36Sopenharmony_ci * configuration 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_cistatic void skl_set_base_outfmt_format(struct skl_dev *skl, 81562306a36Sopenharmony_ci struct skl_module_cfg *mconfig, 81662306a36Sopenharmony_ci struct skl_base_outfmt_cfg *base_outfmt_mcfg) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; 81962306a36Sopenharmony_ci struct skl_base_cfg *base_cfg = 82062306a36Sopenharmony_ci (struct skl_base_cfg *)base_outfmt_mcfg; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci skl_set_base_module_format(skl, mconfig, base_cfg); 82362306a36Sopenharmony_ci skl_setup_out_format(skl, mconfig, out_fmt); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic u16 skl_get_module_param_size(struct skl_dev *skl, 82762306a36Sopenharmony_ci struct skl_module_cfg *mconfig) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct skl_module_res *res; 83062306a36Sopenharmony_ci struct skl_module *module = mconfig->module; 83162306a36Sopenharmony_ci u16 param_size; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci switch (mconfig->m_type) { 83462306a36Sopenharmony_ci case SKL_MODULE_TYPE_COPIER: 83562306a36Sopenharmony_ci param_size = sizeof(struct skl_cpr_cfg); 83662306a36Sopenharmony_ci param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; 83762306a36Sopenharmony_ci return param_size; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci case SKL_MODULE_TYPE_SRCINT: 84062306a36Sopenharmony_ci return sizeof(struct skl_src_module_cfg); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci case SKL_MODULE_TYPE_UPDWMIX: 84362306a36Sopenharmony_ci return sizeof(struct skl_up_down_mixer_cfg); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci case SKL_MODULE_TYPE_BASE_OUTFMT: 84662306a36Sopenharmony_ci case SKL_MODULE_TYPE_MIC_SELECT: 84762306a36Sopenharmony_ci return sizeof(struct skl_base_outfmt_cfg); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci case SKL_MODULE_TYPE_MIXER: 85062306a36Sopenharmony_ci case SKL_MODULE_TYPE_KPB: 85162306a36Sopenharmony_ci return sizeof(struct skl_base_cfg); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci case SKL_MODULE_TYPE_ALGO: 85462306a36Sopenharmony_ci default: 85562306a36Sopenharmony_ci res = &module->resources[mconfig->res_idx]; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci param_size = sizeof(struct skl_base_cfg) + sizeof(struct skl_base_cfg_ext); 85862306a36Sopenharmony_ci param_size += (res->nr_input_pins + res->nr_output_pins) * 85962306a36Sopenharmony_ci sizeof(struct skl_pin_format); 86062306a36Sopenharmony_ci param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return param_size; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return 0; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/* 86962306a36Sopenharmony_ci * DSP firmware supports various modules like copier, SRC, updown etc. 87062306a36Sopenharmony_ci * These modules required various parameters to be calculated and sent for 87162306a36Sopenharmony_ci * the module initialization to DSP. By default a generic module needs only 87262306a36Sopenharmony_ci * base module format configuration 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int skl_set_module_format(struct skl_dev *skl, 87662306a36Sopenharmony_ci struct skl_module_cfg *module_config, 87762306a36Sopenharmony_ci u16 *module_config_size, 87862306a36Sopenharmony_ci void **param_data) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci u16 param_size; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci param_size = skl_get_module_param_size(skl, module_config); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci *param_data = kzalloc(param_size, GFP_KERNEL); 88562306a36Sopenharmony_ci if (NULL == *param_data) 88662306a36Sopenharmony_ci return -ENOMEM; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci *module_config_size = param_size; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci switch (module_config->m_type) { 89162306a36Sopenharmony_ci case SKL_MODULE_TYPE_COPIER: 89262306a36Sopenharmony_ci skl_set_copier_format(skl, module_config, *param_data); 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci case SKL_MODULE_TYPE_SRCINT: 89662306a36Sopenharmony_ci skl_set_src_format(skl, module_config, *param_data); 89762306a36Sopenharmony_ci break; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci case SKL_MODULE_TYPE_UPDWMIX: 90062306a36Sopenharmony_ci skl_set_updown_mixer_format(skl, module_config, *param_data); 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci case SKL_MODULE_TYPE_BASE_OUTFMT: 90462306a36Sopenharmony_ci case SKL_MODULE_TYPE_MIC_SELECT: 90562306a36Sopenharmony_ci skl_set_base_outfmt_format(skl, module_config, *param_data); 90662306a36Sopenharmony_ci break; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci case SKL_MODULE_TYPE_MIXER: 90962306a36Sopenharmony_ci case SKL_MODULE_TYPE_KPB: 91062306a36Sopenharmony_ci skl_set_base_module_format(skl, module_config, *param_data); 91162306a36Sopenharmony_ci break; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci case SKL_MODULE_TYPE_ALGO: 91462306a36Sopenharmony_ci default: 91562306a36Sopenharmony_ci skl_set_base_module_format(skl, module_config, *param_data); 91662306a36Sopenharmony_ci skl_set_base_ext_module_format(skl, module_config, 91762306a36Sopenharmony_ci *param_data + 91862306a36Sopenharmony_ci sizeof(struct skl_base_cfg)); 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", 92362306a36Sopenharmony_ci module_config->m_type, module_config->id.module_id, 92462306a36Sopenharmony_ci param_size); 92562306a36Sopenharmony_ci print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, 92662306a36Sopenharmony_ci *param_data, param_size, false); 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic int skl_get_queue_index(struct skl_module_pin *mpin, 93162306a36Sopenharmony_ci struct skl_module_inst_id id, int max) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci int i; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci for (i = 0; i < max; i++) { 93662306a36Sopenharmony_ci if (mpin[i].id.module_id == id.module_id && 93762306a36Sopenharmony_ci mpin[i].id.instance_id == id.instance_id) 93862306a36Sopenharmony_ci return i; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return -EINVAL; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci/* 94562306a36Sopenharmony_ci * Allocates queue for each module. 94662306a36Sopenharmony_ci * if dynamic, the pin_index is allocated 0 to max_pin. 94762306a36Sopenharmony_ci * In static, the pin_index is fixed based on module_id and instance id 94862306a36Sopenharmony_ci */ 94962306a36Sopenharmony_cistatic int skl_alloc_queue(struct skl_module_pin *mpin, 95062306a36Sopenharmony_ci struct skl_module_cfg *tgt_cfg, int max) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci int i; 95362306a36Sopenharmony_ci struct skl_module_inst_id id = tgt_cfg->id; 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * if pin in dynamic, find first free pin 95662306a36Sopenharmony_ci * otherwise find match module and instance id pin as topology will 95762306a36Sopenharmony_ci * ensure a unique pin is assigned to this so no need to 95862306a36Sopenharmony_ci * allocate/free 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_ci for (i = 0; i < max; i++) { 96162306a36Sopenharmony_ci if (mpin[i].is_dynamic) { 96262306a36Sopenharmony_ci if (!mpin[i].in_use && 96362306a36Sopenharmony_ci mpin[i].pin_state == SKL_PIN_UNBIND) { 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci mpin[i].in_use = true; 96662306a36Sopenharmony_ci mpin[i].id.module_id = id.module_id; 96762306a36Sopenharmony_ci mpin[i].id.instance_id = id.instance_id; 96862306a36Sopenharmony_ci mpin[i].id.pvt_id = id.pvt_id; 96962306a36Sopenharmony_ci mpin[i].tgt_mcfg = tgt_cfg; 97062306a36Sopenharmony_ci return i; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci } else { 97362306a36Sopenharmony_ci if (mpin[i].id.module_id == id.module_id && 97462306a36Sopenharmony_ci mpin[i].id.instance_id == id.instance_id && 97562306a36Sopenharmony_ci mpin[i].pin_state == SKL_PIN_UNBIND) { 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci mpin[i].tgt_mcfg = tgt_cfg; 97862306a36Sopenharmony_ci return i; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci return -EINVAL; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic void skl_free_queue(struct skl_module_pin *mpin, int q_index) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci if (mpin[q_index].is_dynamic) { 98962306a36Sopenharmony_ci mpin[q_index].in_use = false; 99062306a36Sopenharmony_ci mpin[q_index].id.module_id = 0; 99162306a36Sopenharmony_ci mpin[q_index].id.instance_id = 0; 99262306a36Sopenharmony_ci mpin[q_index].id.pvt_id = 0; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci mpin[q_index].pin_state = SKL_PIN_UNBIND; 99562306a36Sopenharmony_ci mpin[q_index].tgt_mcfg = NULL; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* Module state will be set to unint, if all the out pin state is UNBIND */ 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic void skl_clear_module_state(struct skl_module_pin *mpin, int max, 100162306a36Sopenharmony_ci struct skl_module_cfg *mcfg) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci int i; 100462306a36Sopenharmony_ci bool found = false; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci for (i = 0; i < max; i++) { 100762306a36Sopenharmony_ci if (mpin[i].pin_state == SKL_PIN_UNBIND) 100862306a36Sopenharmony_ci continue; 100962306a36Sopenharmony_ci found = true; 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (!found) 101462306a36Sopenharmony_ci mcfg->m_state = SKL_MODULE_INIT_DONE; 101562306a36Sopenharmony_ci return; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci/* 101962306a36Sopenharmony_ci * A module needs to be instanataited in DSP. A mdoule is present in a 102062306a36Sopenharmony_ci * collection of module referred as a PIPE. 102162306a36Sopenharmony_ci * We first calculate the module format, based on module type and then 102262306a36Sopenharmony_ci * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ciint skl_init_module(struct skl_dev *skl, 102562306a36Sopenharmony_ci struct skl_module_cfg *mconfig) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci u16 module_config_size = 0; 102862306a36Sopenharmony_ci void *param_data = NULL; 102962306a36Sopenharmony_ci int ret; 103062306a36Sopenharmony_ci struct skl_ipc_init_instance_msg msg; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, 103362306a36Sopenharmony_ci mconfig->id.module_id, mconfig->id.pvt_id); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (mconfig->pipe->state != SKL_PIPE_CREATED) { 103662306a36Sopenharmony_ci dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", 103762306a36Sopenharmony_ci mconfig->pipe->state, mconfig->pipe->ppl_id); 103862306a36Sopenharmony_ci return -EIO; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ret = skl_set_module_format(skl, mconfig, 104262306a36Sopenharmony_ci &module_config_size, ¶m_data); 104362306a36Sopenharmony_ci if (ret < 0) { 104462306a36Sopenharmony_ci dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); 104562306a36Sopenharmony_ci return ret; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci msg.module_id = mconfig->id.module_id; 104962306a36Sopenharmony_ci msg.instance_id = mconfig->id.pvt_id; 105062306a36Sopenharmony_ci msg.ppl_instance_id = mconfig->pipe->ppl_id; 105162306a36Sopenharmony_ci msg.param_data_size = module_config_size; 105262306a36Sopenharmony_ci msg.core_id = mconfig->core_id; 105362306a36Sopenharmony_ci msg.domain = mconfig->domain; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); 105662306a36Sopenharmony_ci if (ret < 0) { 105762306a36Sopenharmony_ci dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); 105862306a36Sopenharmony_ci kfree(param_data); 105962306a36Sopenharmony_ci return ret; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci mconfig->m_state = SKL_MODULE_INIT_DONE; 106262306a36Sopenharmony_ci kfree(param_data); 106362306a36Sopenharmony_ci return ret; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg 106762306a36Sopenharmony_ci *src_module, struct skl_module_cfg *dst_module) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", 107062306a36Sopenharmony_ci __func__, src_module->id.module_id, src_module->id.pvt_id); 107162306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, 107262306a36Sopenharmony_ci dst_module->id.module_id, dst_module->id.pvt_id); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", 107562306a36Sopenharmony_ci src_module->m_state, dst_module->m_state); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/* 107962306a36Sopenharmony_ci * On module freeup, we need to unbind the module with modules 108062306a36Sopenharmony_ci * it is already bind. 108162306a36Sopenharmony_ci * Find the pin allocated and unbind then using bind_unbind IPC 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_ciint skl_unbind_modules(struct skl_dev *skl, 108462306a36Sopenharmony_ci struct skl_module_cfg *src_mcfg, 108562306a36Sopenharmony_ci struct skl_module_cfg *dst_mcfg) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci int ret; 108862306a36Sopenharmony_ci struct skl_ipc_bind_unbind_msg msg; 108962306a36Sopenharmony_ci struct skl_module_inst_id src_id = src_mcfg->id; 109062306a36Sopenharmony_ci struct skl_module_inst_id dst_id = dst_mcfg->id; 109162306a36Sopenharmony_ci int in_max = dst_mcfg->module->max_input_pins; 109262306a36Sopenharmony_ci int out_max = src_mcfg->module->max_output_pins; 109362306a36Sopenharmony_ci int src_index, dst_index, src_pin_state, dst_pin_state; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci skl_dump_bind_info(skl, src_mcfg, dst_mcfg); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* get src queue index */ 109862306a36Sopenharmony_ci src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); 109962306a36Sopenharmony_ci if (src_index < 0) 110062306a36Sopenharmony_ci return 0; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci msg.src_queue = src_index; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* get dst queue index */ 110562306a36Sopenharmony_ci dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); 110662306a36Sopenharmony_ci if (dst_index < 0) 110762306a36Sopenharmony_ci return 0; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci msg.dst_queue = dst_index; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; 111262306a36Sopenharmony_ci dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (src_pin_state != SKL_PIN_BIND_DONE || 111562306a36Sopenharmony_ci dst_pin_state != SKL_PIN_BIND_DONE) 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci msg.module_id = src_mcfg->id.module_id; 111962306a36Sopenharmony_ci msg.instance_id = src_mcfg->id.pvt_id; 112062306a36Sopenharmony_ci msg.dst_module_id = dst_mcfg->id.module_id; 112162306a36Sopenharmony_ci msg.dst_instance_id = dst_mcfg->id.pvt_id; 112262306a36Sopenharmony_ci msg.bind = false; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci ret = skl_ipc_bind_unbind(&skl->ipc, &msg); 112562306a36Sopenharmony_ci if (!ret) { 112662306a36Sopenharmony_ci /* free queue only if unbind is success */ 112762306a36Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 112862306a36Sopenharmony_ci skl_free_queue(dst_mcfg->m_in_pin, dst_index); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci /* 113162306a36Sopenharmony_ci * check only if src module bind state, bind is 113262306a36Sopenharmony_ci * always from src -> sink 113362306a36Sopenharmony_ci */ 113462306a36Sopenharmony_ci skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return ret; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci#define CPR_SINK_FMT_PARAM_ID 2 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci/* 114362306a36Sopenharmony_ci * Once a module is instantiated it need to be 'bind' with other modules in 114462306a36Sopenharmony_ci * the pipeline. For binding we need to find the module pins which are bind 114562306a36Sopenharmony_ci * together 114662306a36Sopenharmony_ci * This function finds the pins and then sends bund_unbind IPC message to 114762306a36Sopenharmony_ci * DSP using IPC helper 114862306a36Sopenharmony_ci */ 114962306a36Sopenharmony_ciint skl_bind_modules(struct skl_dev *skl, 115062306a36Sopenharmony_ci struct skl_module_cfg *src_mcfg, 115162306a36Sopenharmony_ci struct skl_module_cfg *dst_mcfg) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci int ret = 0; 115462306a36Sopenharmony_ci struct skl_ipc_bind_unbind_msg msg; 115562306a36Sopenharmony_ci int in_max = dst_mcfg->module->max_input_pins; 115662306a36Sopenharmony_ci int out_max = src_mcfg->module->max_output_pins; 115762306a36Sopenharmony_ci int src_index, dst_index; 115862306a36Sopenharmony_ci struct skl_module_fmt *format; 115962306a36Sopenharmony_ci struct skl_cpr_pin_fmt pin_fmt; 116062306a36Sopenharmony_ci struct skl_module *module; 116162306a36Sopenharmony_ci struct skl_module_iface *fmt; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci skl_dump_bind_info(skl, src_mcfg, dst_mcfg); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || 116662306a36Sopenharmony_ci dst_mcfg->m_state < SKL_MODULE_INIT_DONE) 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); 117062306a36Sopenharmony_ci if (src_index < 0) 117162306a36Sopenharmony_ci return -EINVAL; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci msg.src_queue = src_index; 117462306a36Sopenharmony_ci dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); 117562306a36Sopenharmony_ci if (dst_index < 0) { 117662306a36Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 117762306a36Sopenharmony_ci return -EINVAL; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* 118162306a36Sopenharmony_ci * Copier module requires the separate large_config_set_ipc to 118262306a36Sopenharmony_ci * configure the pins other than 0 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) { 118562306a36Sopenharmony_ci pin_fmt.sink_id = src_index; 118662306a36Sopenharmony_ci module = src_mcfg->module; 118762306a36Sopenharmony_ci fmt = &module->formats[src_mcfg->fmt_idx]; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* Input fmt is same as that of src module input cfg */ 119062306a36Sopenharmony_ci format = &fmt->inputs[0].fmt; 119162306a36Sopenharmony_ci fill_pin_params(&(pin_fmt.src_fmt), format); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci format = &fmt->outputs[src_index].fmt; 119462306a36Sopenharmony_ci fill_pin_params(&(pin_fmt.dst_fmt), format); 119562306a36Sopenharmony_ci ret = skl_set_module_params(skl, (void *)&pin_fmt, 119662306a36Sopenharmony_ci sizeof(struct skl_cpr_pin_fmt), 119762306a36Sopenharmony_ci CPR_SINK_FMT_PARAM_ID, src_mcfg); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (ret < 0) 120062306a36Sopenharmony_ci goto out; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci msg.dst_queue = dst_index; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", 120662306a36Sopenharmony_ci msg.src_queue, msg.dst_queue); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci msg.module_id = src_mcfg->id.module_id; 120962306a36Sopenharmony_ci msg.instance_id = src_mcfg->id.pvt_id; 121062306a36Sopenharmony_ci msg.dst_module_id = dst_mcfg->id.module_id; 121162306a36Sopenharmony_ci msg.dst_instance_id = dst_mcfg->id.pvt_id; 121262306a36Sopenharmony_ci msg.bind = true; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci ret = skl_ipc_bind_unbind(&skl->ipc, &msg); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (!ret) { 121762306a36Sopenharmony_ci src_mcfg->m_state = SKL_MODULE_BIND_DONE; 121862306a36Sopenharmony_ci src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; 121962306a36Sopenharmony_ci dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; 122062306a36Sopenharmony_ci return ret; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ciout: 122362306a36Sopenharmony_ci /* error case , if IPC fails, clear the queue index */ 122462306a36Sopenharmony_ci skl_free_queue(src_mcfg->m_out_pin, src_index); 122562306a36Sopenharmony_ci skl_free_queue(dst_mcfg->m_in_pin, dst_index); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci return ret; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, 123162306a36Sopenharmony_ci enum skl_ipc_pipeline_state state) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci/* 123962306a36Sopenharmony_ci * A pipeline is a collection of modules. Before a module in instantiated a 124062306a36Sopenharmony_ci * pipeline needs to be created for it. 124162306a36Sopenharmony_ci * This function creates pipeline, by sending create pipeline IPC messages 124262306a36Sopenharmony_ci * to FW 124362306a36Sopenharmony_ci */ 124462306a36Sopenharmony_ciint skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci int ret; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, 125162306a36Sopenharmony_ci pipe->pipe_priority, pipe->ppl_id, 125262306a36Sopenharmony_ci pipe->lp_mode); 125362306a36Sopenharmony_ci if (ret < 0) { 125462306a36Sopenharmony_ci dev_err(skl->dev, "Failed to create pipeline\n"); 125562306a36Sopenharmony_ci return ret; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci pipe->state = SKL_PIPE_CREATED; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci/* 126462306a36Sopenharmony_ci * A pipeline needs to be deleted on cleanup. If a pipeline is running, 126562306a36Sopenharmony_ci * then pause it first. Before actual deletion, pipeline should enter 126662306a36Sopenharmony_ci * reset state. Finish the procedure by sending delete pipeline IPC. 126762306a36Sopenharmony_ci * DSP will stop the DMA engines and release resources 126862306a36Sopenharmony_ci */ 126962306a36Sopenharmony_ciint skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci int ret; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* If pipe was not created in FW, do not try to delete it */ 127662306a36Sopenharmony_ci if (pipe->state < SKL_PIPE_CREATED) 127762306a36Sopenharmony_ci return 0; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* If pipe is started, do stop the pipe in FW. */ 128062306a36Sopenharmony_ci if (pipe->state >= SKL_PIPE_STARTED) { 128162306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 128262306a36Sopenharmony_ci if (ret < 0) { 128362306a36Sopenharmony_ci dev_err(skl->dev, "Failed to stop pipeline\n"); 128462306a36Sopenharmony_ci return ret; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* reset pipe state before deletion */ 129162306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RESET); 129262306a36Sopenharmony_ci if (ret < 0) { 129362306a36Sopenharmony_ci dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); 129462306a36Sopenharmony_ci return ret; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci pipe->state = SKL_PIPE_RESET; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); 130062306a36Sopenharmony_ci if (ret < 0) { 130162306a36Sopenharmony_ci dev_err(skl->dev, "Failed to delete pipeline\n"); 130262306a36Sopenharmony_ci return ret; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci pipe->state = SKL_PIPE_INVALID; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci return ret; 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci/* 131162306a36Sopenharmony_ci * A pipeline is also a scheduling entity in DSP which can be run, stopped 131262306a36Sopenharmony_ci * For processing data the pipe need to be run by sending IPC set pipe state 131362306a36Sopenharmony_ci * to DSP 131462306a36Sopenharmony_ci */ 131562306a36Sopenharmony_ciint skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci int ret; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 132262306a36Sopenharmony_ci if (pipe->state < SKL_PIPE_CREATED) 132362306a36Sopenharmony_ci return 0; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* Pipe has to be paused before it is started */ 132662306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 132762306a36Sopenharmony_ci if (ret < 0) { 132862306a36Sopenharmony_ci dev_err(skl->dev, "Failed to pause pipe\n"); 132962306a36Sopenharmony_ci return ret; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); 133562306a36Sopenharmony_ci if (ret < 0) { 133662306a36Sopenharmony_ci dev_err(skl->dev, "Failed to start pipe\n"); 133762306a36Sopenharmony_ci return ret; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci pipe->state = SKL_PIPE_STARTED; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci return 0; 134362306a36Sopenharmony_ci} 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci/* 134662306a36Sopenharmony_ci * Stop the pipeline by sending set pipe state IPC 134762306a36Sopenharmony_ci * DSP doesnt implement stop so we always send pause message 134862306a36Sopenharmony_ci */ 134962306a36Sopenharmony_ciint skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci int ret; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 135662306a36Sopenharmony_ci if (pipe->state < SKL_PIPE_PAUSED) 135762306a36Sopenharmony_ci return 0; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); 136062306a36Sopenharmony_ci if (ret < 0) { 136162306a36Sopenharmony_ci dev_dbg(skl->dev, "Failed to stop pipe\n"); 136262306a36Sopenharmony_ci return ret; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci pipe->state = SKL_PIPE_PAUSED; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci/* 137162306a36Sopenharmony_ci * Reset the pipeline by sending set pipe state IPC this will reset the DMA 137262306a36Sopenharmony_ci * from the DSP side 137362306a36Sopenharmony_ci */ 137462306a36Sopenharmony_ciint skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci int ret; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* If pipe was not created in FW, do not try to pause or delete */ 137962306a36Sopenharmony_ci if (pipe->state < SKL_PIPE_PAUSED) 138062306a36Sopenharmony_ci return 0; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci ret = skl_set_pipe_state(skl, pipe, PPL_RESET); 138362306a36Sopenharmony_ci if (ret < 0) { 138462306a36Sopenharmony_ci dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); 138562306a36Sopenharmony_ci return ret; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci pipe->state = SKL_PIPE_RESET; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return 0; 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci/* Algo parameter set helper function */ 139462306a36Sopenharmony_ciint skl_set_module_params(struct skl_dev *skl, u32 *params, int size, 139562306a36Sopenharmony_ci u32 param_id, struct skl_module_cfg *mcfg) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci struct skl_ipc_large_config_msg msg; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci msg.module_id = mcfg->id.module_id; 140062306a36Sopenharmony_ci msg.instance_id = mcfg->id.pvt_id; 140162306a36Sopenharmony_ci msg.param_data_size = size; 140262306a36Sopenharmony_ci msg.large_param_id = param_id; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return skl_ipc_set_large_config(&skl->ipc, &msg, params); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ciint skl_get_module_params(struct skl_dev *skl, u32 *params, int size, 140862306a36Sopenharmony_ci u32 param_id, struct skl_module_cfg *mcfg) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci struct skl_ipc_large_config_msg msg; 141162306a36Sopenharmony_ci size_t bytes = size; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci msg.module_id = mcfg->id.module_id; 141462306a36Sopenharmony_ci msg.instance_id = mcfg->id.pvt_id; 141562306a36Sopenharmony_ci msg.param_data_size = size; 141662306a36Sopenharmony_ci msg.large_param_id = param_id; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); 141962306a36Sopenharmony_ci} 1420