diff options
Diffstat (limited to 'sound/soc/intel/skylake')
-rw-r--r-- | sound/soc/intel/skylake/bxt-sst.c | 174 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-messages.c | 23 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-nhlt.c | 65 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 289 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-cldma.c | 26 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-cldma.h | 2 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-dsp.c | 6 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-dsp.h | 40 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.c | 76 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.h | 22 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-utils.c | 140 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst.c | 178 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 344 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.h | 14 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-tplg-interface.h | 12 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.c | 14 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.h | 6 |
17 files changed, 933 insertions, 498 deletions
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1f9f33d34000..f5e7dbb1ba39 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -23,10 +23,10 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "skl-sst-ipc.h" -#include "skl-tplg-interface.h" #define BXT_BASEFW_TIMEOUT 3000 -#define BXT_INIT_TIMEOUT 500 +#define BXT_INIT_TIMEOUT 300 +#define BXT_ROM_INIT_TIMEOUT 70 #define BXT_IPC_PURGE_FW 0x01004000 #define BXT_ROM_INIT 0x5 @@ -46,39 +46,27 @@ /* Delay before scheduling D0i3 entry */ #define BXT_D0I3_DELAY 5000 +#define BXT_FW_ROM_INIT_RETRY 3 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); } static int -bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) +bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; struct skl_sst *skl = ctx->thread_context; - const struct firmware *fw = NULL; struct firmware stripped_fw; int ret = 0, i, dma_id, stream_tag; /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < minfo->lib_count; i++) { - ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request lib %s failed:%d\n", - minfo->lib[i].name, ret); - return ret; - } - - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, fw, + for (i = 1; i < lib_count; i++) { + ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, BXT_ADSP_FW_BIN_HDR_OFFSET, i); - if (ret < 0) - goto load_library_failed; - } - - stripped_fw.data = fw->data; - stripped_fw.size = fw->size; - skl_dsp_strip_extended_manifest(&stripped_fw); + if (ret < 0) + goto load_library_failed; stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, stripped_fw.size, &dmab); @@ -93,21 +81,19 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) memcpy(dmab.area, stripped_fw.data, stripped_fw.size); ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); - ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i); + ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true); if (ret < 0) dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", - minfo->lib[i].name, ret); + linfo[i].name, ret); ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); - release_firmware(fw); - fw = NULL; } return ret; load_library_failed: - release_firmware(fw); + skl_release_library(linfo, lib_count); return ret; } @@ -119,8 +105,7 @@ load_library_failed: static int sst_bxt_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) { - int stream_tag, ret, i; - u32 reg; + int stream_tag, ret; stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); if (stream_tag <= 0) { @@ -153,23 +138,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, } /* Step 4: Wait for DONE Bit */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); - - if (reg & SKL_ADSP_REG_HIPCIE_DONE) { - sst_dsp_shim_update_bits_forced(ctx, - SKL_ADSP_REG_HIPCIE, + ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE, SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); - break; - } - mdelay(1); - } - if (!i) { - dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); + SKL_ADSP_REG_HIPCIE_DONE, + BXT_INIT_TIMEOUT, "HIPCIE Done"); + if (ret < 0) { + dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret); + goto base_fw_load_failed; } /* Step 5: power down core1 */ @@ -184,19 +159,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, skl_ipc_op_int_enable(ctx); /* Step 7: Wait for ROM init */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - if (SKL_FW_INIT == - (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & - SKL_FW_STS_MASK)) { - - dev_info(ctx->dev, "ROM loaded, continue FW loading\n"); - break; - } - mdelay(1); - } - if (!i) { - dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg); - ret = -EIO; + ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, + SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load"); + if (ret < 0) { + dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); goto base_fw_load_failed; } @@ -227,18 +193,16 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; struct skl_sst *skl = ctx->thread_context; - int ret; + int ret, i; - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - goto sst_load_base_firmware_failed; + if (ctx->fw == NULL) { + ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + return ret; + } } - /* check for extended manifest */ - if (ctx->fw == NULL) - goto sst_load_base_firmware_failed; - /* prase uuids on first boot */ if (skl->is_first_boot) { ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); @@ -250,18 +214,20 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) stripped_fw.size = ctx->fw->size; skl_dsp_strip_extended_manifest(&stripped_fw); - ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - /* Retry Enabling core and ROM load. Retry seemed to help */ - if (ret < 0) { + + for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (ret < 0) { - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", + if (ret == 0) + break; + } + + if (ret < 0) { + dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); - goto sst_load_base_firmware_failed; - } + dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); + goto sst_load_base_firmware_failed; } ret = sst_transfer_fw_host_dma(ctx); @@ -286,8 +252,11 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) } } + return ret; + sst_load_base_firmware_failed: release_firmware(ctx->fw); + ctx->fw = NULL; return ret; } @@ -432,7 +401,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_dfw_manifest *minfo = &skl->manifest; if (skl->fw_loaded == false) { skl->boot_complete = false; @@ -442,13 +410,15 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) return ret; } - if (minfo->lib_count > 1) { - ret = bxt_load_library(ctx, minfo); + if (skl->lib_count > 1) { + ret = bxt_load_library(ctx, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(ctx->dev, "reload libs failed: %d\n", ret); return ret; } } + skl->cores.state[core_id] = SKL_DSP_RUNNING; return ret; } @@ -535,11 +505,22 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) + if (ret < 0) { dev_err(ctx->dev, "Failed to set DSP to D3:core id = %d;Continue reset\n", core_id); + /* + * In case of D3 failure, re-download the firmware, so set + * fw_loaded to false. + */ + skl->fw_loaded = false; + } + if (core_id == SKL_DSP_CORE0_ID) { + /* disable Interrupt */ + skl_ipc_op_int_disable(ctx); + skl_ipc_int_disable(ctx); + } ret = skl_dsp_disable_core(ctx, core_mask); if (ret < 0) { dev_err(ctx->dev, "Failed to disable core %d\n", ret); @@ -581,23 +562,14 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, struct sst_dsp *sst; int ret; - skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); - if (skl == NULL) - return -ENOMEM; - - skl->dev = dev; - skl_dev.thread_context = skl; - INIT_LIST_HEAD(&skl->uuid_list); - - skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); - if (!skl->dsp) { - dev_err(skl->dev, "skl_dsp_ctx_init failed\n"); - return -ENODEV; + ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); + if (ret < 0) { + dev_err(dev, "%s: no device\n", __func__); + return ret; } + skl = *dsp; sst = skl->dsp; - sst->fw_name = fw_name; - sst->dsp_ops = dsp_ops; sst->fw_ops = bxt_fw_ops; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; @@ -605,24 +577,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - INIT_LIST_HEAD(&sst->module_list); - ret = skl_ipc_init(dev, skl); - if (ret) - return ret; - /* set the D0i3 check */ skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; skl->cores.count = 2; skl->boot_complete = false; init_waitqueue_head(&skl->boot_wait); - skl->is_first_boot = true; INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); skl->d0i3.state = SKL_DSP_D0I3_NONE; - if (dsp) - *dsp = skl; - return 0; } EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); @@ -640,8 +603,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->manifest.lib_count > 1) { - ret = sst->fw_ops.load_library(sst, &ctx->manifest); + if (ctx->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, ctx->lib_info, + ctx->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; @@ -655,6 +619,10 @@ EXPORT_SYMBOL_GPL(bxt_sst_init_fw); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + + skl_release_library(ctx->lib_info, ctx->lib_count); + if (ctx->dsp->fw) + release_firmware(ctx->dsp->fw); skl_freeup_uuid_list(ctx); skl_ipc_free(&ctx->ipc); ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e79cbcf6e462..ab1adc0c9cc3 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -58,7 +58,7 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) #define NOTIFICATION_MASK 0xf /* disable notfication for underruns/overruns from firmware module */ -static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) +void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) { struct notification_mask mask; struct skl_ipc_large_config_msg msg = {0}; @@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = { { .id = 0x9d71, .loader_ops = skl_get_loader_ops, - .init = skl_sst_dsp_init, + .init = kbl_sst_dsp_init, .init_fw = skl_sst_init_fw, .cleanup = skl_sst_dsp_cleanup }, @@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = { .init_fw = bxt_sst_init_fw, .cleanup = bxt_sst_dsp_cleanup }, + { + .id = 0x3198, + .loader_ops = bxt_get_loader_ops, + .init = bxt_sst_dsp_init, + .init_fw = bxt_sst_init_fw, + .cleanup = bxt_sst_dsp_cleanup + }, }; const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) @@ -267,6 +274,7 @@ int skl_init_dsp(struct skl *skl) if (ret < 0) return ret; + skl->skl_sst->dsp_ops = ops; dev_dbg(bus->dev, "dsp registration status=%d\n", ret); return ret; @@ -277,16 +285,11 @@ int skl_free_dsp(struct skl *skl) struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl_sst *ctx = skl->skl_sst; - const struct skl_dsp_ops *ops; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) - return -EIO; - - ops->cleanup(bus->dev, ctx); + ctx->dsp_ops->cleanup(bus->dev, ctx); if (ctx->dsp->addr.lpe) iounmap(ctx->dsp->addr.lpe); @@ -859,7 +862,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max, } if (!found) - mcfg->m_state = SKL_MODULE_UNINIT; + mcfg->m_state = SKL_MODULE_INIT_DONE; return; } @@ -1091,7 +1094,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe is started, do stop the pipe in FW. */ - if (pipe->state > SKL_PIPE_STARTED) { + if (pipe->state >= SKL_PIPE_STARTED) { ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); if (ret < 0) { dev_err(ctx->dev, "Failed to stop pipeline\n"); diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 3f8e6f0b7eb5..e3f06672fd6d 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -24,8 +24,6 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; -#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" - struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) { acpi_handle handle; @@ -33,8 +31,9 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) struct nhlt_resource_desc *nhlt_ptr = NULL; struct nhlt_acpi_table *nhlt_table = NULL; - if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { - dev_err(dev, "Requested NHLT device not found\n"); + handle = ACPI_HANDLE(dev); + if (!handle) { + dev_err(dev, "Didn't find ACPI_HANDLE\n"); return NULL; } @@ -102,14 +101,16 @@ static void dump_config(struct device *dev, u32 instance_id, u8 linktype, } static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, - u32 instance_id, u8 link_type, u8 dirn) + u32 instance_id, u8 link_type, u8 dirn, u8 dev_type) { - dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n", - epnt->virtual_bus_id, epnt->linktype, epnt->direction); + dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n", + epnt->virtual_bus_id, epnt->linktype, + epnt->direction, epnt->device_type); if ((epnt->virtual_bus_id == instance_id) && (epnt->linktype == link_type) && - (epnt->direction == dirn)) + (epnt->direction == dirn) && + (epnt->device_type == dev_type)) return true; else return false; @@ -117,7 +118,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, - u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn) + u8 s_fmt, u8 num_ch, u32 s_rate, + u8 dirn, u8 dev_type) { struct nhlt_fmt *fmt; struct nhlt_endpoint *epnt; @@ -135,7 +137,8 @@ struct nhlt_specific_cfg dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); for (j = 0; j < nhlt->endpoint_count; j++) { - if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { + if (skl_check_ep_match(dev, epnt, instance, link_type, + dirn, dev_type)) { fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); sp_config = skl_get_specific_cfg(dev, fmt, num_ch, @@ -189,9 +192,9 @@ int skl_get_dmic_geo(struct skl *skl) return dmic_geo; } -static void skl_nhlt_trim_space(struct skl *skl) +static void skl_nhlt_trim_space(char *trim) { - char *s = skl->tplg_name; + char *s = trim; int cnt; int i; @@ -218,7 +221,43 @@ int skl_nhlt_update_topology_bin(struct skl *skl) skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, nhlt->header.oem_revision, "-tplg.bin"); - skl_nhlt_trim_space(skl); + skl_nhlt_trim_space(skl->tplg_name); + + return 0; +} + +static ssize_t skl_nhlt_platform_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + char platform_id[32]; + + sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, + nhlt->header.oem_id, nhlt->header.oem_table_id, + nhlt->header.oem_revision); + + skl_nhlt_trim_space(platform_id); + return sprintf(buf, "%s\n", platform_id); +} + +static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); + +int skl_nhlt_create_sysfs(struct skl *skl) +{ + struct device *dev = &skl->pci->dev; + + if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) + dev_warn(dev, "Error creating sysfs entry\n"); return 0; } + +void skl_nhlt_remove_sysfs(struct skl *skl) +{ + struct device *dev = &skl->pci->dev; + + sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); +} diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 84b5101e6ca6..e91bbcffc856 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -21,6 +21,7 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> +#include <linux/delay.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include "skl.h" @@ -137,6 +138,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, skl->supend_active--; } +int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + int err; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->host_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + + format_val = snd_hdac_calc_stream_format(params->s_freq, + params->ch, params->format, params->host_bps, 0); + + dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_stream_reset(hdac_stream(stream)); + err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); + if (err < 0) + return err; + + err = snd_hdac_stream_setup(hdac_stream(stream)); + if (err < 0) + return err; + + hdac_stream(stream)->prepared = 1; + + return 0; +} + +int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + struct hdac_ext_link *link; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->link_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, + params->format, params->link_bps, 0); + + dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_ext_link_stream_reset(stream); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + list_for_each_entry(link, &ebus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + hstream->stream_tag); + } + + stream->link_prepared = 1; + + return 0; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -180,88 +255,30 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, snd_pcm_set_sync(substream); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + if (!mconfig) + return -EINVAL; + skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); return 0; } -static int skl_get_format(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct skl_dma_params *dma_params; - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - int format_val = 0; - - if ((ebus_to_hbus(ebus))->ppcap) { - struct snd_pcm_runtime *runtime = substream->runtime; - - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - 32, 0); - } else { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - } - - return format_val; -} - -static int skl_be_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl *skl = get_skl_ctx(dai->dev); - struct skl_sst *ctx = skl->skl_sst; - struct skl_module_cfg *mconfig; - - if (dai->playback_widget->power || dai->capture_widget->power) - return 0; - - mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig == NULL) - return -EINVAL; - - return skl_dsp_set_dma_control(ctx, mconfig); -} - static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct skl *skl = get_skl_ctx(dai->dev); - unsigned int format_val; - int err; struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - format_val = skl_get_format(substream, dai); - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", - hdac_stream(stream)->stream_tag, format_val); - snd_hdac_stream_reset(hdac_stream(stream)); - /* In case of XRUN recovery, reset the FW pipe to clean state */ if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); - if (err < 0) - return err; - - err = snd_hdac_stream_setup(hdac_stream(stream)); - if (err < 0) - return err; - - hdac_stream(stream)->prepared = 1; - - return err; + return 0; } static int skl_pcm_hw_params(struct snd_pcm_substream *substream, @@ -292,6 +309,12 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, p_params.s_freq = params_rate(params); p_params.host_dma_id = dma_id; p_params.stream = substream->stream; + p_params.format = params_format(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.host_bps = dai->driver->playback.sig_bits; + else + p_params.host_bps = dai->driver->capture.sig_bits; + m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); if (m_cfg) @@ -435,7 +458,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: if (!w->ignore_suspend) { - skl_pcm_prepare(substream, dai); /* * enable DMA Resume enable bit for the stream, set the * dpib & lpib position to resume before starting the @@ -444,7 +466,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, snd_hdac_ext_stream_drsm_enable(ebus, true, hdac_stream(stream)->index); snd_hdac_ext_stream_set_dpibr(ebus, stream, - stream->dpib); + stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } @@ -456,7 +478,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, * pipeline is started but there is a delay in starting the * DMA channel on the host. */ - snd_hdac_ext_stream_decouple(ebus, stream, true); ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; @@ -503,9 +524,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; + struct hdac_ext_link *link; + int stream_tag; link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -514,16 +536,27 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + /* set the stream tag in the codec dai dma params */ - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_dma_id = stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.link_bps = codec_dai->driver->playback.sig_bits; + else + p_params.link_bps = codec_dai->driver->capture.sig_bits; return skl_tplg_be_update_params(dai, &p_params); } @@ -531,41 +564,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - unsigned int format_val = 0; - struct skl_dma_params *dma_params; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct hdac_ext_link *link; struct skl *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; - dma_params = (struct skl_dma_params *) - snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", - hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); - if (!link) - return -EINVAL; - - snd_hdac_ext_link_stream_reset(link_dev); - /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig && (substream->runtime->status->state == - SNDRV_PCM_STATE_XRUN)) + if (mconfig && !mconfig->pipe->passthru && + (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - snd_hdac_ext_link_stream_setup(link_dev, format_val); - - snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); - link_dev->link_prepared = 1; - return 0; } @@ -580,10 +587,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; @@ -638,7 +643,6 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { .hw_params = skl_be_hw_params, - .prepare = skl_be_prepare, }; static struct snd_soc_dai_ops skl_link_dai_ops = { @@ -659,6 +663,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, .capture = { .stream_name = "System Capture", @@ -666,6 +671,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -677,6 +683,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -688,6 +695,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -699,6 +707,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -710,6 +719,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -725,6 +735,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, { @@ -740,6 +751,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, { @@ -755,6 +767,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, @@ -938,14 +951,12 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { static int skl_platform_open(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *dai_link = rtd->dai_link; dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, dai_link->cpu_dai_name); - runtime = substream->runtime; snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); return 0; @@ -1051,13 +1062,31 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer * HAD space reflects the actual data that is transferred. * Use the position buffer for capture, as DPIB write gets * completed earlier than the actual data written to the DDR. + * + * For capture stream following workaround is required to fix the + * incorrect position reporting. + * + * 1. Wait for 20us before reading the DMA position in buffer once + * the interrupt is generated for stream completion as update happens + * on the HDA frame boundary i.e. 20.833uSec. + * 2. Read DPIB register to flush the DMA position value. This dummy + * read is required to flush DMA position value. + * 3. Read the DMA Position-in-Buffer. This value now will be equal to + * or greater than period boundary. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(hstream)->index)); - else + } else { + udelay(20); + readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + } if (pos >= hdac_stream(hstream)->bufsize) pos = 0; @@ -1154,7 +1183,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_pci_data(skl->pci), size, MAX_PREALLOC_SIZE); if (retval) { - dev_err(dai->dev, "dma buffer allocationf fail\n"); + dev_err(dai->dev, "dma buffer allocation fail\n"); return retval; } } @@ -1162,29 +1191,52 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } +static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) +{ + struct skl_sst *ctx = skl->skl_sst; + struct uuid_module *module; + uuid_le *uuid_mod; + + uuid_mod = (uuid_le *)mconfig->guid; + + if (list_empty(&ctx->uuid_list)) { + dev_err(ctx->dev, "Module list is empty\n"); + return -EIO; + } + + list_for_each_entry(module, &ctx->uuid_list, list) { + if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { + mconfig->id.module_id = module->id; + mconfig->is_loadable = module->is_loadable; + return 0; + } + } + + return -EIO; +} + static int skl_populate_modules(struct skl *skl) { struct skl_pipeline *p; struct skl_pipe_module *m; struct snd_soc_dapm_widget *w; struct skl_module_cfg *mconfig; - int ret; + int ret = 0; list_for_each_entry(p, &skl->ppl_list, node) { list_for_each_entry(m, &p->pipe->w_list, node) { - w = m->w; mconfig = w->priv; - ret = snd_skl_get_module_info(skl->skl_sst, mconfig); + ret = skl_get_module_info(skl, mconfig); if (ret < 0) { dev_err(skl->skl_sst->dev, - "query module info failed:%d\n", ret); - goto err; + "query module info failed\n"); + return ret; } } } -err: + return ret; } @@ -1221,6 +1273,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) } skl_populate_modules(skl); skl->skl_sst->update_d0i3c = skl_update_d0i3c; + skl_dsp_enable_notification(skl->skl_sst, false); } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); @@ -1245,6 +1298,7 @@ int skl_platform_register(struct device *dev) struct skl *skl = ebus_to_skl(ebus); INIT_LIST_HEAD(&skl->ppl_list); + INIT_LIST_HEAD(&skl->bind_list); ret = snd_soc_register_platform(dev, &skl_platform_drv); if (ret) { @@ -1265,6 +1319,17 @@ int skl_platform_register(struct device *dev) int skl_platform_unregister(struct device *dev) { + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct skl *skl = ebus_to_skl(ebus); + struct skl_module_deferred_bind *modules, *tmp; + + if (!list_empty(&skl->bind_list)) { + list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { + list_del(&modules->node); + kfree(modules); + } + } + snd_soc_unregister_component(dev); snd_soc_unregister_platform(dev); return 0; diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index c9f6d87381db..d2b1d60fec02 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -164,7 +164,7 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx) ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); } -static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +int skl_cldma_wait_interruptible(struct sst_dsp *ctx) { int ret = 0; @@ -243,9 +243,14 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, * 2. Polling on fw register to identify if data left to transferred doesn't * fill the ring buffer. Caller takes care of polling the required status * register to identify the transfer status. + * 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till + * bytes_left is 0. + * if wait flag is not set, doesn't wait for BDL interrupt. after ccopying + * the first chunk return the no of bytes_left to be copied. */ static int -skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, + u32 total_size, bool wait) { int ret = 0; bool start = true; @@ -272,13 +277,14 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) size = ctx->cl_dev.bufsize; skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); - start = false; - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) { - skl_cldma_stop(ctx); - return ret; + if (wait) { + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } } - } else { skl_cldma_int_disable(ctx); @@ -298,9 +304,11 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) } bytes_left -= size; curr_pos = curr_pos + size; + if (!wait) + return bytes_left; } - return ret; + return bytes_left; } void skl_cldma_process_intr(struct sst_dsp *ctx) diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 99e4c86b6358..5b730a1a0ae4 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -213,7 +213,7 @@ struct skl_cl_dev_ops { void (*cl_trigger)(struct sst_dsp *ctx, bool enable); void (*cl_cleanup_controller)(struct sst_dsp *ctx); int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, - const void *bin, u32 size); + const void *bin, u32 size, bool wait); void (*cl_stop_dma)(struct sst_dsp *ctx); }; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index c3deefab65d6..08332723c700 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -355,12 +355,13 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) ret = ctx->fw_ops.set_state_D0(ctx, core_id); if (ret < 0) { dev_err(ctx->dev, "unable to get core%d\n", core_id); - return ret; + goto out; } } skl->cores.usage_count[core_id]++; +out: dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", core_id, skl->cores.state[core_id], skl->cores.usage_count[core_id]); @@ -379,7 +380,8 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) return -EINVAL; } - if (--skl->cores.usage_count[core_id] == 0) { + if ((--skl->cores.usage_count[core_id] == 0) && + (skl->cores.state[core_id] != SKL_DSP_RESET)) { ret = ctx->fw_ops.set_state_D3(ctx, core_id); if (ret < 0) { dev_err(ctx->dev, "unable to put core %d: %d\n", diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 7c272ba0f4b5..eba20d37ba8c 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,14 +17,15 @@ #define __SKL_SST_DSP_H__ #include <linux/interrupt.h> +#include <linux/uuid.h> +#include <linux/firmware.h> #include <sound/memalloc.h> #include "skl-sst-cldma.h" -#include "skl-tplg-interface.h" -#include "skl-topology.h" struct sst_dsp; struct skl_sst; struct sst_dsp_device; +struct skl_lib_info; /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 @@ -145,7 +146,7 @@ struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ int (*load_library)(struct sst_dsp *ctx, - struct skl_dfw_manifest *minfo); + struct skl_lib_info *linfo, int lib_count); int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); @@ -173,6 +174,19 @@ struct skl_dsp_loader_ops { int stream_tag); }; +#define MAX_INSTANCE_BUFF 2 + +struct uuid_module { + uuid_le uuid; + int id; + int is_loadable; + int max_instance; + u64 pvt_id[MAX_INSTANCE_BUFF]; + int *instance_id; + + struct list_head list; +}; + struct skl_load_module_info { u16 mod_id; const struct firmware *fw; @@ -187,6 +201,7 @@ struct skl_module_table { void skl_cldma_process_intr(struct sst_dsp *ctx); void skl_cldma_int_disable(struct sst_dsp *ctx); int skl_cldma_prepare(struct sst_dsp *ctx); +int skl_cldma_wait_interruptible(struct sst_dsp *ctx); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, @@ -215,6 +230,9 @@ int skl_dsp_boot(struct sst_dsp *ctx); int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_sst **dsp); int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); @@ -223,18 +241,22 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); -int snd_skl_get_module_info(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, unsigned int offset, int index); -int skl_get_pvt_id(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); -int skl_put_pvt_id(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); +int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id); +int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id); int skl_get_pvt_instance_id_map(struct skl_sst *ctx, int module_id, int instance_id); void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); +void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); +int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct sst_dsp_device *skl_dev); +int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, + struct firmware *stripped_fw, + unsigned int hdr_offset, int index); +void skl_release_library(struct skl_lib_info *linfo, int lib_count); #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index e1391dfbc9e9..58c525096a7c 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -34,6 +34,11 @@ #define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) #define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) +#define IPC_GLB_REPLY_TYPE_SHIFT 29 +#define IPC_GLB_REPLY_TYPE_MASK 0x1F +#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \ + & IPC_GLB_RPLY_TYPE_MASK) + #define IPC_TIMEOUT_MSECS 3000 #define IPC_EMPTY_LIST_SIZE 8 @@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, return 0; } +static int skl_ipc_set_reply_error_code(u32 reply) +{ + switch (reply) { + case IPC_GLB_REPLY_OUT_OF_MEMORY: + return -ENOMEM; + + case IPC_GLB_REPLY_BUSY: + return -EBUSY; + + default: + return -EINVAL; + } +} + static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, struct skl_ipc_header header) { struct ipc_message *msg; u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u64 *ipc_header = (u64 *)(&header); + struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); msg = skl_ipc_reply_get_msg(ipc, *ipc_header); if (msg == NULL) { @@ -401,33 +421,39 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, } /* first process the header */ - switch (reply) { - case IPC_GLB_REPLY_SUCCESS: + if (reply == IPC_GLB_REPLY_SUCCESS) { dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); /* copy the rx data from the mailbox */ sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); - break; - - case IPC_GLB_REPLY_OUT_OF_MEMORY: - dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); - msg->errno = -ENOMEM; - break; - - case IPC_GLB_REPLY_BUSY: - dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); - msg->errno = -EBUSY; - break; + switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + case IPC_GLB_LOAD_MULTIPLE_MODS: + case IPC_GLB_LOAD_LIBRARY: + skl->mod_load_complete = true; + skl->mod_load_status = true; + wake_up(&skl->mod_load_wait); + break; - default: - dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply); - msg->errno = -EINVAL; - break; - } + default: + break; - if (reply != IPC_GLB_REPLY_SUCCESS) { + } + } else { + msg->errno = skl_ipc_set_reply_error_code(reply); dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); dev_err(ipc->dev, "FW Error Code: %u\n", ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + case IPC_GLB_LOAD_MULTIPLE_MODS: + case IPC_GLB_LOAD_LIBRARY: + skl->mod_load_complete = true; + skl->mod_load_status = false; + wake_up(&skl->mod_load_wait); + break; + + default: + break; + + } } list_del(&msg->list); @@ -811,8 +837,8 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt), NULL, 0); + ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt)); if (ret < 0) dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); @@ -947,7 +973,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id) + u8 dma_id, u8 table_id, bool wait) { struct skl_ipc_header header = {0}; u64 *ipc_header = (u64 *)(&header); @@ -959,7 +985,11 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, header.primary |= IPC_MOD_INSTANCE_ID(table_id); header.primary |= IPC_MOD_ID(dma_id); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (wait) + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, + NULL, 0, NULL, 0); + else + ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, NULL, 0); if (ret < 0) dev_err(ipc->dev, "ipc: load lib failed\n"); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index cc40341233fa..e057da2713c6 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -69,6 +69,14 @@ struct skl_d0i3_data { struct delayed_work work; }; +#define SKL_LIB_NAME_LENGTH 128 +#define SKL_MAX_LIB 16 + +struct skl_lib_info { + char name[SKL_LIB_NAME_LENGTH]; + const struct firmware *fw; +}; + struct skl_sst { struct device *dev; struct sst_dsp *dsp; @@ -77,6 +85,11 @@ struct skl_sst { wait_queue_head_t boot_wait; bool boot_complete; + /* module load */ + wait_queue_head_t mod_load_wait; + bool mod_load_complete; + bool mod_load_status; + /* IPC messaging */ struct sst_generic_ipc ipc; @@ -97,13 +110,16 @@ struct skl_sst { /* multi-core */ struct skl_dsp_cores cores; - /* tplg manifest */ - struct skl_dfw_manifest manifest; + /* library info */ + struct skl_lib_info lib_info[SKL_MAX_LIB]; + int lib_count; /* Callback to update D0i3C register */ void (*update_d0i3c)(struct device *dev, bool enable); struct skl_d0i3_data d0i3; + + const struct skl_dsp_ops *dsp_ops; }; struct skl_ipc_init_instance_msg { @@ -181,7 +197,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id); + u8 dma_id, u8 table_id, bool wait); int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg); diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index ea162fbf68e5..81ee251881b4 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -94,19 +94,6 @@ struct adsp_fw_hdr { u32 load_offset; } __packed; -#define MAX_INSTANCE_BUFF 2 - -struct uuid_module { - uuid_le uuid; - int id; - int is_loadable; - int max_instance; - u64 pvt_id[MAX_INSTANCE_BUFF]; - int *instance_id; - - struct list_head list; -}; - struct skl_ext_manifest_hdr { u32 id; u32 len; @@ -115,32 +102,6 @@ struct skl_ext_manifest_hdr { u32 entries; }; -int snd_skl_get_module_info(struct skl_sst *ctx, - struct skl_module_cfg *mconfig) -{ - struct uuid_module *module; - uuid_le *uuid_mod; - - uuid_mod = (uuid_le *)mconfig->guid; - - if (list_empty(&ctx->uuid_list)) { - dev_err(ctx->dev, "Module list is empty\n"); - return -EINVAL; - } - - list_for_each_entry(module, &ctx->uuid_list, list) { - if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { - mconfig->id.module_id = module->id; - mconfig->is_loadable = module->is_loadable; - - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_skl_get_module_info); - static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) { int pvt_id; @@ -222,21 +183,18 @@ static inline int skl_pvtid_128(struct uuid_module *module) * This generates a 128 bit private unique id for a module TYPE so that * module instance is unique */ -int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id) { struct uuid_module *module; - uuid_le *uuid_mod; int pvt_id; - uuid_mod = (uuid_le *)mconfig->guid; - list_for_each_entry(module, &ctx->uuid_list, list) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { pvt_id = skl_pvtid_128(module); if (pvt_id >= 0) { - module->instance_id[pvt_id] = - mconfig->id.instance_id; + module->instance_id[pvt_id] = instance_id; + return pvt_id; } } @@ -254,23 +212,21 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); * * This frees a 128 bit private unique id previously generated */ -int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id) { int i; - uuid_le *uuid_mod; struct uuid_module *module; - uuid_mod = (uuid_le *)mconfig->guid; list_for_each_entry(module, &ctx->uuid_list, list) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { - if (mconfig->id.pvt_id != 0) - i = (mconfig->id.pvt_id) / 64; + if (*pvt_id != 0) + i = (*pvt_id) / 64; else i = 0; - module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id)); - mconfig->id.pvt_id = -1; + module->pvt_id[i] &= ~(1 << (*pvt_id)); + *pvt_id = -1; return 0; } } @@ -405,3 +361,83 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw) return 0; } + +int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct sst_dsp_device *skl_dev) +{ + struct skl_sst *skl; + struct sst_dsp *sst; + int ret; + + skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); + if (skl == NULL) + return -ENOMEM; + + skl->dev = dev; + skl_dev->thread_context = skl; + INIT_LIST_HEAD(&skl->uuid_list); + skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq); + if (!skl->dsp) { + dev_err(skl->dev, "%s: no device\n", __func__); + return -ENODEV; + } + + sst = skl->dsp; + sst->fw_name = fw_name; + sst->dsp_ops = dsp_ops; + init_waitqueue_head(&skl->mod_load_wait); + INIT_LIST_HEAD(&sst->module_list); + ret = skl_ipc_init(dev, skl); + if (ret) + return ret; + + skl->is_first_boot = true; + if (dsp) + *dsp = skl; + + return ret; +} + +int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, + struct firmware *stripped_fw, + unsigned int hdr_offset, int index) +{ + int ret; + struct sst_dsp *dsp = skl->dsp; + + if (linfo->fw == NULL) { + ret = request_firmware(&linfo->fw, linfo->name, + skl->dev); + if (ret < 0) { + dev_err(skl->dev, "Request lib %s failed:%d\n", + linfo->name, ret); + return ret; + } + } + + if (skl->is_first_boot) { + ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index); + if (ret < 0) + return ret; + } + + stripped_fw->data = linfo->fw->data; + stripped_fw->size = linfo->fw->size; + skl_dsp_strip_extended_manifest(stripped_fw); + + return 0; +} + +void skl_release_library(struct skl_lib_info *linfo, int lib_count) +{ + int i; + + /* library indices start from 1 to N. 0 represents base FW */ + for (i = 1; i < lib_count; i++) { + if (linfo[i].fw) { + release_firmware(linfo[i].fw); + linfo[i].fw = NULL; + } + } +} diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 8fc3178bc79c..155e456b7a3a 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -52,7 +52,8 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, { int ret = 0; - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size, + true); if (ret < 0) return ret; @@ -178,6 +179,18 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) dev_err(ctx->dev, "unable to load firmware\n"); return ret; } + + /* load libs as they are also lost on D3 */ + if (skl->lib_count > 1) { + ret = ctx->fw_ops.load_library(ctx, skl->lib_info, + skl->lib_count); + if (ret < 0) { + dev_err(ctx->dev, "reload libs failed: %d\n", + ret); + return ret; + } + + } } /* @@ -203,7 +216,7 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) skl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; + return 0; } static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) @@ -323,27 +336,85 @@ static struct skl_module_table *skl_module_get_from_id( return NULL; } -static int skl_transfer_module(struct sst_dsp *ctx, - struct skl_load_module_info *module) +static int skl_transfer_module(struct sst_dsp *ctx, const void *data, + u32 size, u16 mod_id, u8 table_id, bool is_module) { - int ret; + int ret, bytes_left, curr_pos; struct skl_sst *skl = ctx->thread_context; + skl->mod_load_complete = false; - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data, - module->fw->size); - if (ret < 0) - return ret; + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); + if (bytes_left < 0) + return bytes_left; - ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, - (void *)&module->mod_id); - if (ret < 0) - dev_err(ctx->dev, "Failed to Load module: %d\n", ret); + /* check is_module flag to load module or library */ + if (is_module) + ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); + else + ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false); + + if (ret < 0) { + dev_err(ctx->dev, "Failed to Load %s with err %d\n", + is_module ? "module" : "lib", ret); + goto out; + } + + /* + * if bytes_left > 0 then wait for BDL complete interrupt and + * copy the next chunk till bytes_left is 0. if bytes_left is + * is zero, then wait for load module IPC reply + */ + while (bytes_left > 0) { + curr_pos = size - bytes_left; + + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) + goto out; + + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, + data + curr_pos, + bytes_left, false); + } + ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0 || !skl->mod_load_status) { + dev_err(ctx->dev, "Module Load failed\n"); + ret = -EIO; + } + +out: ctx->cl_dev.ops.cl_stop_dma(ctx); return ret; } +static int +kbl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) +{ + struct skl_sst *skl = ctx->thread_context; + struct firmware stripped_fw; + int ret, i; + + /* library indices start from 1 to N. 0 represents base FW */ + for (i = 1; i < lib_count; i++) { + ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, + SKL_ADSP_FW_BIN_HDR_OFFSET, i); + if (ret < 0) + goto load_library_failed; + ret = skl_transfer_module(ctx, stripped_fw.data, + stripped_fw.size, 0, i, false); + if (ret < 0) + goto load_library_failed; + } + + return 0; + +load_library_failed: + skl_release_library(linfo, lib_count); + return ret; +} + static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) { struct skl_module_table *module_entry = NULL; @@ -365,7 +436,9 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) } if (!module_entry->usage_cnt) { - ret = skl_transfer_module(ctx, module_entry->mod_info); + ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data, + module_entry->mod_info->fw->size, + mod_id, 0, true); if (ret < 0) { dev_err(ctx->dev, "Failed to Load module\n"); return ret; @@ -388,6 +461,11 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); return -EIO; } + + /* if module is used by others return, no need to unload */ + if (usage_cnt > 0) + return 0; + ret = skl_ipc_unload_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); if (ret < 0) { @@ -434,6 +512,16 @@ static struct skl_dsp_fw_ops skl_fw_ops = { .unload_mod = skl_unload_module, }; +static struct skl_dsp_fw_ops kbl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, + .load_library = kbl_load_library, + .load_mod = skl_load_module, + .unload_mod = skl_unload_module, +}; + static struct sst_ops skl_ops = { .irq_handler = skl_dsp_sst_interrupt, .write = sst_shim32_write, @@ -455,45 +543,47 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, struct sst_dsp *sst; int ret; - skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); - if (skl == NULL) - return -ENOMEM; - - skl->dev = dev; - skl_dev.thread_context = skl; - INIT_LIST_HEAD(&skl->uuid_list); - - skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); - if (!skl->dsp) { - dev_err(skl->dev, "%s: no device\n", __func__); - return -ENODEV; + ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); + if (ret < 0) { + dev_err(dev, "%s: no device\n", __func__); + return ret; } + skl = *dsp; sst = skl->dsp; - - sst->fw_name = fw_name; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - INIT_LIST_HEAD(&sst->module_list); - sst->dsp_ops = dsp_ops; sst->fw_ops = skl_fw_ops; - ret = skl_ipc_init(dev, skl); - if (ret) + skl->cores.count = 2; + + return 0; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_sst **dsp) +{ + struct sst_dsp *sst; + int ret; + + ret = skl_sst_dsp_init(dev, mmio_base, irq, fw_name, dsp_ops, dsp); + if (ret < 0) { + dev_err(dev, "%s: Init failed %d\n", __func__, ret); return ret; + } - skl->cores.count = 2; - skl->is_first_boot = true; + sst = (*dsp)->dsp; + sst->fw_ops = kbl_fw_ops; - if (dsp) - *dsp = skl; + return 0; - return ret; } -EXPORT_SYMBOL_GPL(skl_sst_dsp_init); +EXPORT_SYMBOL_GPL(kbl_sst_dsp_init); int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) { @@ -507,6 +597,15 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) } skl_dsp_init_core_state(sst); + + if (ctx->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, ctx->lib_info, + ctx->lib_count); + if (ret < 0) { + dev_err(dev, "Load Library failed : %x\n", ret); + return ret; + } + } ctx->is_first_boot = false; return 0; @@ -515,6 +614,9 @@ EXPORT_SYMBOL_GPL(skl_sst_init_fw); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + + if (ctx->dsp->fw) + release_firmware(ctx->dsp->fw); skl_clear_module_table(ctx->dsp); skl_freeup_uuid_list(ctx); skl_ipc_free(&ctx->ipc); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index bd313c907b20..3a99712e44a8 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -299,8 +299,6 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, { int multiplier = 1; struct skl_module_fmt *in_fmt, *out_fmt; - int in_rate, out_rate; - /* Since fixups is applied to pin 0 only, ibs, obs needs * change for pin 0 only @@ -311,23 +309,38 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - if (in_fmt->s_freq % 1000) - in_rate = (in_fmt->s_freq / 1000) + 1; - else - in_rate = (in_fmt->s_freq / 1000); + mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * + in_fmt->channels * (in_fmt->bit_depth >> 3) * + multiplier; - mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * - (mcfg->in_fmt->bit_depth >> 3) * + mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * + out_fmt->channels * (out_fmt->bit_depth >> 3) * multiplier; +} - if (mcfg->out_fmt->s_freq % 1000) - out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; - else - out_rate = (mcfg->out_fmt->s_freq / 1000); +static u8 skl_tplg_be_dev_type(int dev_type) +{ + int ret; - mcfg->obs = out_rate * (mcfg->out_fmt->channels) * - (mcfg->out_fmt->bit_depth >> 3) * - multiplier; + switch (dev_type) { + case SKL_DEVICE_BT: + ret = NHLT_DEVICE_BT; + break; + + case SKL_DEVICE_DMIC: + ret = NHLT_DEVICE_DMIC; + break; + + case SKL_DEVICE_I2S: + ret = NHLT_DEVICE_I2S; + break; + + default: + ret = NHLT_DEVICE_INVALID; + break; + } + + return ret; } static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, @@ -338,6 +351,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, u32 ch, s_freq, s_fmt; struct nhlt_specific_cfg *cfg; struct skl *skl = get_skl_ctx(ctx->dev); + u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); /* check if we already have blob */ if (m_cfg->formats_config.caps_size > 0) @@ -374,7 +388,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, /* update the blob based on virtual bus_id and default params */ cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, - s_fmt, ch, s_freq, dir); + s_fmt, ch, s_freq, dir, dev_type); if (cfg) { m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps = (u32 *) &cfg->caps; @@ -486,7 +500,7 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) if (bc->set_params != SKL_PARAM_INIT) continue; - mconfig->formats_config.caps = (u32 *)&bc->params; + mconfig->formats_config.caps = (u32 *)bc->params; mconfig->formats_config.caps_size = bc->size; break; @@ -496,6 +510,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) return 0; } +static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, + struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) +{ + switch (mcfg->dev_type) { + case SKL_DEVICE_HDAHOST: + return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); + + case SKL_DEVICE_HDALINK: + return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + } + + return 0; +} + /* * Inside a pipe instance, we can have various modules. These modules need * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by @@ -511,6 +539,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) int ret = 0; list_for_each_entry(w_module, &pipe->w_list, node) { + uuid_le *uuid_mod; w = w_module->w; mconfig = w->priv; @@ -535,6 +564,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig->m_state = SKL_MODULE_LOADED; } + /* prepare the DMA if the module is gateway cpr */ + ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + if (ret < 0) + return ret; + /* update blob if blob is null for be with default value */ skl_tplg_update_be_blob(w, ctx); @@ -543,13 +577,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) * FE/BE params */ skl_tplg_update_module_params(w, ctx); - mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig); + uuid_mod = (uuid_le *)mconfig->guid; + mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, + mconfig->id.instance_id); if (mconfig->id.pvt_id < 0) return ret; skl_tplg_set_module_init_data(w); ret = skl_init_module(ctx, mconfig); if (ret < 0) { - skl_put_pvt_id(ctx, mconfig); + skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); return ret; } skl_tplg_alloc_pipe_mcps(skl, mconfig); @@ -569,7 +605,9 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, struct skl_module_cfg *mconfig = NULL; list_for_each_entry(w_module, &pipe->w_list, node) { + uuid_le *uuid_mod; mconfig = w_module->w->priv; + uuid_mod = (uuid_le *)mconfig->guid; if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && mconfig->m_state > SKL_MODULE_UNINIT) { @@ -578,7 +616,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, if (ret < 0) return -EIO; } - skl_put_pvt_id(ctx, mconfig); + skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); } /* no modules to unload in this path, so return */ @@ -600,8 +638,9 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_cfg *src_module = NULL, *dst_module; + struct skl_module_cfg *src_module = NULL, *dst_module, *module; struct skl_sst *ctx = skl->skl_sst; + struct skl_module_deferred_bind *modules; /* check resource available */ if (!skl_is_pipe_mcps_avail(skl, mconfig)) @@ -642,29 +681,48 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } + /* + * When the destination module is initialized, check for these modules + * in deferred bind list. If found, bind them. + */ + list_for_each_entry(w_module, &s_pipe->w_list, node) { + if (list_empty(&skl->bind_list)) + break; + + list_for_each_entry(modules, &skl->bind_list, node) { + module = w_module->w->priv; + if (modules->dst == module) + skl_bind_modules(ctx, modules->src, + modules->dst); + } + } + return 0; } -static int skl_fill_sink_instance_id(struct skl_sst *ctx, - struct skl_algo_data *alg_data) +static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, + int size, struct skl_module_cfg *mcfg) { - struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params; - struct skl_mod_inst_map *inst; int i, pvt_id; - inst = params->map; + if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { + struct skl_kpb_params *kpb_params = + (struct skl_kpb_params *)params; + struct skl_mod_inst_map *inst = kpb_params->map; - for (i = 0; i < params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(ctx, - inst->mod_id, inst->inst_id); - if (pvt_id < 0) - return -EINVAL; - inst->inst_id = pvt_id; - inst++; + for (i = 0; i < kpb_params->num_modules; i++) { + pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id, + inst->inst_id); + if (pvt_id < 0) + return -EINVAL; + + inst->inst_id = pvt_id; + inst++; + } } + return 0; } - /* * Some modules require params to be set after the module is bound to * all pins connected. @@ -681,6 +739,7 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, struct soc_bytes_ext *sb; struct skl_algo_data *bc; struct skl_specific_cfg *sp_cfg; + u32 *params; /* * check all out/in pins are in bind state. @@ -713,11 +772,18 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - if (mconfig->m_type == SKL_MODULE_TYPE_KPB) - skl_fill_sink_instance_id(ctx, bc); - ret = skl_set_module_params(ctx, - (u32 *)bc->params, bc->max, - bc->param_id, mconfig); + params = kzalloc(bc->max, GFP_KERNEL); + if (!params) + return -ENOMEM; + + memcpy(params, bc->params, bc->max); + skl_fill_sink_instance_id(ctx, params, bc->max, + mconfig); + + ret = skl_set_module_params(ctx, params, + bc->max, bc->param_id, mconfig); + kfree(params); + if (ret < 0) return ret; } @@ -727,6 +793,44 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, return 0; } + +static int skl_tplg_module_add_deferred_bind(struct skl *skl, + struct skl_module_cfg *src, struct skl_module_cfg *dst) +{ + struct skl_module_deferred_bind *m_list, *modules; + int i; + + /* only supported for module with static pin connection */ + for (i = 0; i < dst->max_in_queue; i++) { + struct skl_module_pin *pin = &dst->m_in_pin[i]; + + if (pin->is_dynamic) + continue; + + if ((pin->id.module_id == src->id.module_id) && + (pin->id.instance_id == src->id.instance_id)) { + + if (!list_empty(&skl->bind_list)) { + list_for_each_entry(modules, &skl->bind_list, node) { + if (modules->src == src && modules->dst == dst) + return 0; + } + } + + m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); + if (!m_list) + return -ENOMEM; + + m_list->src = src; + m_list->dst = dst; + + list_add(&m_list->node, &skl->bind_list); + } + } + + return 0; +} + static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, struct skl *skl, struct snd_soc_dapm_widget *src_w, @@ -761,6 +865,28 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, sink = p->sink; sink_mconfig = sink->priv; + /* + * Modules other than PGA leaf can be connected + * directly or via switch to a module in another + * pipeline. EX: reference path + * when the path is enabled, the dst module that needs + * to be bound may not be initialized. if the module is + * not initialized, add these modules in the deferred + * bind list and when the dst module is initialised, + * bind this module to the dst_module in deferred list. + */ + if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) + && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { + + ret = skl_tplg_module_add_deferred_bind(skl, + src_mconfig, sink_mconfig); + + if (ret < 0) + return ret; + + } + + if (src_mconfig->m_state == SKL_MODULE_UNINIT || sink_mconfig->m_state == SKL_MODULE_UNINIT) continue; @@ -940,15 +1066,6 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; if (!src_mconfig) continue; - /* - * If path_found == 1, that means pmd for source - * pipe has not occurred, source is connected to - * some other sink. so its responsibility of sink - * to unbind itself from source. - */ - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); @@ -974,7 +1091,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, struct skl_module_cfg *src_module = NULL, *dst_module; struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; - int ret = 0; + struct skl_module_deferred_bind *modules, *tmp; if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; @@ -983,6 +1100,35 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, skl_tplg_free_pipe_mem(skl, mconfig); list_for_each_entry(w_module, &s_pipe->w_list, node) { + if (list_empty(&skl->bind_list)) + break; + + src_module = w_module->w->priv; + + list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { + /* + * When the destination module is deleted, Unbind the + * modules from deferred bind list. + */ + if (modules->dst == src_module) { + skl_unbind_modules(ctx, modules->src, + modules->dst); + } + + /* + * When the source module is deleted, remove this entry + * from the deferred bind list. + */ + if (modules->src == src_module) { + list_del(&modules->node); + modules->src = NULL; + modules->dst = NULL; + kfree(modules); + } + } + } + + list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; if (mconfig->m_state >= SKL_MODULE_INIT_DONE) @@ -996,7 +1142,12 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } - ret = skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(ctx, mconfig->pipe); + + list_for_each_entry(w_module, &s_pipe->w_list, node) { + src_module = w_module->w->priv; + src_module->m_state = SKL_MODULE_UNINIT; + } return skl_tplg_unload_pipe_modules(ctx, s_pipe); } @@ -1039,36 +1190,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, } /* - * In modelling, we assume there will be ONLY one mixer in a pipeline. If - * mixer is not required then it is treated as static mixer aka vmixer with - * a hard path to source module - * So we don't need to check if source is started or not as hard path puts - * dependency on each other - */ -static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMU: - return skl_tplg_mixer_dapm_post_pmu_event(w, skl); - - case SND_SOC_DAPM_PRE_PMD: - return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_mixer_dapm_post_pmd_event(w, skl); - } - - return 0; -} - -/* * In modelling, we assume there will be ONLY one mixer in a pipeline. If a * second one is required that is created as another pipe entity. * The mixer is responsible for pipe management and represent a pipeline @@ -1207,10 +1328,13 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, switch (mcfg->dev_type) { case SKL_DEVICE_HDALINK: pipe->p_params->link_dma_id = params->link_dma_id; + pipe->p_params->link_index = params->link_index; + pipe->p_params->link_bps = params->link_bps; break; case SKL_DEVICE_HDAHOST: pipe->p_params->host_dma_id = params->host_dma_id; + pipe->p_params->host_bps = params->host_bps; break; default: @@ -1220,6 +1344,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, pipe->p_params->ch = params->ch; pipe->p_params->s_freq = params->s_freq; pipe->p_params->stream = params->stream; + pipe->p_params->format = params->format; } else { memcpy(pipe->p_params, params, sizeof(*params)); @@ -1428,6 +1553,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, struct nhlt_specific_cfg *cfg; struct skl *skl = get_skl_ctx(dai->dev); int link_type = skl_tplg_be_link_type(mconfig->dev_type); + u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); skl_tplg_fill_dma_id(mconfig, params); @@ -1437,7 +1563,8 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, /* update the blob based on virtual bus_id*/ cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, params->s_fmt, params->ch, - params->s_freq, params->stream); + params->s_freq, params->stream, + dev_type); if (cfg) { mconfig->formats_config.caps_size = cfg->size; mconfig->formats_config.caps = (u32 *) &cfg->caps; @@ -1530,7 +1657,7 @@ int skl_tplg_be_update_params(struct snd_soc_dai *dai, static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { {SKL_MIXER_EVENT, skl_tplg_mixer_event}, - {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, + {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, {SKL_PGA_EVENT, skl_tplg_pga_event}, }; @@ -1584,7 +1711,7 @@ static int skl_tplg_add_pipe(struct device *dev, list_for_each_entry(ppl, &skl->ppl_list, node) { if (ppl->pipe->ppl_id == tkn_elem->value) { mconfig->pipe = ppl->pipe; - return EEXIST; + return -EEXIST; } } @@ -1876,11 +2003,13 @@ static int skl_tplg_get_token(struct device *dev, ret = skl_tplg_add_pipe(dev, mconfig, skl, tkn_elem); - if (ret < 0) + if (ret < 0) { + if (ret == -EEXIST) { + is_pipe_exists = 1; + break; + } return is_pipe_exists; - - if (ret == EEXIST) - is_pipe_exists = 1; + } break; @@ -2280,20 +2409,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > minfo->lib_count - 1) { + if (ref_count > skl->skl_sst->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(minfo->lib[ref_count].name, str_elem->string, - ARRAY_SIZE(minfo->lib[ref_count].name)); + strncpy(skl->skl_sst->lib_info[ref_count].name, + str_elem->string, + ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); ref_count++; tkn_count++; break; @@ -2308,14 +2438,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; while (tkn_count < array->num_elems) { - ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); + ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); str_elem++; if (ret < 0) @@ -2329,13 +2459,13 @@ static int skl_tplg_get_str_tkn(struct device *dev, static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - minfo->lib_count = tkn_elem->value; + skl->skl_sst->lib_count = tkn_elem->value; tkn_count++; break; @@ -2352,7 +2482,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl_dfw_manifest *minfo, + char *pvt_data, struct skl *skl, int block_size) { int tkn_count = 0, ret; @@ -2368,7 +2498,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, off += array->size; switch (array->type) { case SND_SOC_TPLG_TUPLE_TYPE_STRING: - ret = skl_tplg_get_str_tkn(dev, array, minfo); + ret = skl_tplg_get_str_tkn(dev, array, skl); if (ret < 0) return ret; @@ -2390,7 +2520,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, while (tkn_count <= array->num_elems - 1) { ret = skl_tplg_get_int_tkn(dev, - tkn_elem, minfo); + tkn_elem, skl); if (ret < 0) return ret; @@ -2411,7 +2541,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl_dfw_manifest *minfo) + struct device *dev, struct skl *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -2454,7 +2584,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, data = (manifest->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_manifest_tkn(dev, data, minfo, + ret = skl_tplg_get_manifest_tkn(dev, data, skl, block_size); if (ret < 0) @@ -2472,27 +2602,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, static int skl_manifest_load(struct snd_soc_component *cmpnt, struct snd_soc_tplg_manifest *manifest) { - struct skl_dfw_manifest *minfo; struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl *skl = ebus_to_skl(ebus); - int ret = 0; /* proceed only if we have private data defined */ if (manifest->priv.size == 0) return 0; - minfo = &skl->skl_sst->manifest; - - skl_tplg_get_manifest_data(manifest, bus->dev, minfo); + skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (minfo->lib_count > HDA_MAX_LIB) { + if (skl->skl_sst->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - minfo->lib_count); - ret = -EINVAL; + skl->skl_sst->lib_count); + return -EINVAL; } - return ret; + return 0; } static struct snd_soc_tplg_ops skl_tplg_ops = { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 08d39280b07b..cc64d6bdb4f6 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -254,7 +254,11 @@ struct skl_pipe_params { u32 s_freq; u32 s_fmt; u8 linktype; + snd_pcm_format_t format; + int link_index; int stream; + unsigned int host_bps; + unsigned int link_bps; }; struct skl_pipe { @@ -332,6 +336,12 @@ struct skl_pipeline { struct list_head node; }; +struct skl_module_deferred_bind { + struct skl_module_cfg *src; + struct skl_module_cfg *dst; + struct list_head node; +}; + static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); @@ -383,4 +393,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream); enum skl_bitdepth skl_get_bit_depth(int params); +int skl_pcm_host_dma_prepare(struct device *dev, + struct skl_pipe_params *params); +int skl_pcm_link_dma_prepare(struct device *dev, + struct skl_pipe_params *params); #endif diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 2f6281e056d6..7a2febf99019 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -157,18 +157,6 @@ struct skl_dfw_algo_data { char params[0]; } __packed; -#define LIB_NAME_LENGTH 128 -#define HDA_MAX_LIB 16 - -struct lib_info { - char name[LIB_NAME_LENGTH]; -} __packed; - -struct skl_dfw_manifest { - u32 lib_count; - struct lib_info lib[HDA_MAX_LIB]; -} __packed; - enum skl_tkn_dir { SKL_DIR_IN, SKL_DIR_OUT diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index da5db5098274..6df3b317a476 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -512,7 +512,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr) struct hdac_bus *bus = ebus_to_hbus(ebus); unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; + unsigned int res = -1; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci, goto out_display_power_off; } + err = skl_nhlt_create_sysfs(skl); + if (err < 0) + goto out_nhlt_free; + skl_nhlt_update_topology_bin(skl); pci_set_drvdata(skl->pci, ebus); @@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci) skl_free_dsp(skl); skl_machine_device_unregister(skl); skl_dmic_device_unregister(skl); + skl_nhlt_remove_sysfs(skl); skl_nhlt_free(skl->nhlt); skl_free(ebus); dev_set_drvdata(&pci->dev, NULL); @@ -878,6 +883,10 @@ static struct sst_acpi_mach sst_kbl_devdata[] = { {} }; +static struct sst_acpi_mach sst_glk_devdata[] = { + { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL }, +}; + /* PCI IDs */ static const struct pci_device_id skl_ids[] = { /* Sunrise Point-LP */ @@ -889,6 +898,9 @@ static const struct pci_device_id skl_ids[] = { /* KBL */ { PCI_DEVICE(0x8086, 0x9D71), .driver_data = (unsigned long)&sst_kbl_devdata}, + /* GLK */ + { PCI_DEVICE(0x8086, 0x3198), + .driver_data = (unsigned long)&sst_glk_devdata}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4986e3929dd3..5b3fa4b91691 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -77,6 +77,7 @@ struct skl { struct skl_dsp_resource resource; struct list_head ppl_list; + struct list_head bind_list; const char *fw_name; char tplg_name[64]; @@ -118,7 +119,8 @@ int skl_platform_register(struct device *dev); struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); void skl_nhlt_free(struct nhlt_acpi_table *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, - u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); + u8 link_type, u8 s_fmt, u8 no_ch, + u32 s_rate, u8 dirn, u8 dev_type); int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); @@ -130,5 +132,7 @@ int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); void skl_update_d0i3c(struct device *dev, bool enable); +int skl_nhlt_create_sysfs(struct skl *skl); +void skl_nhlt_remove_sysfs(struct skl *skl); #endif /* __SOUND_SOC_SKL_H */ |