summaryrefslogtreecommitdiff
path: root/sound/soc/intel/skylake
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/skylake')
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c118
-rw-r--r--sound/soc/intel/skylake/skl-messages.c16
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c7
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c118
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c26
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.h2
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h40
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c76
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h17
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c140
-rw-r--r--sound/soc/intel/skylake/skl-sst.c175
-rw-r--r--sound/soc/intel/skylake/skl-topology.c247
-rw-r--r--sound/soc/intel/skylake/skl-topology.h17
-rw-r--r--sound/soc/intel/skylake/skl.c2
-rw-r--r--sound/soc/intel/skylake/skl.h1
16 files changed, 668 insertions, 340 deletions
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index 15a063a403cc..f5e7dbb1ba39 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -25,7 +25,8 @@
#include "skl-sst-ipc.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
@@ -45,6 +46,8 @@
/* 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);
@@ -55,29 +58,15 @@ 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 < lib_count; i++) {
- ret = request_firmware(&fw, linfo[i].name, ctx->dev);
- if (ret < 0) {
- dev_err(ctx->dev, "Request lib %s failed:%d\n",
- linfo[i].name, ret);
- return ret;
- }
-
- if (skl->is_first_boot) {
- ret = snd_skl_parse_uuids(ctx, fw,
+ 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);
@@ -92,21 +81,19 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
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",
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;
}
@@ -156,7 +143,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
SKL_ADSP_REG_HIPCIE_DONE,
BXT_INIT_TIMEOUT, "HIPCIE Done");
if (ret < 0) {
- dev_err(ctx->dev, "Timout for Purge Request%d\n", ret);
+ dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret);
goto base_fw_load_failed;
}
@@ -173,7 +160,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
/* Step 7: Wait for ROM init */
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
- SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load");
+ 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;
@@ -206,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);
@@ -229,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);
@@ -265,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;
}
@@ -428,6 +418,7 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
return ret;
}
}
+ skl->cores.state[core_id] = SKL_DSP_RUNNING;
return ret;
}
@@ -514,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);
@@ -560,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;
@@ -584,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);
@@ -635,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 e66870474f10..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
},
@@ -274,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;
@@ -284,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);
@@ -866,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;
}
@@ -1098,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 7eb9c419dc7f..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;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index e12520e142ff..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"
@@ -155,7 +156,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
snd_hdac_ext_stream_decouple(ebus, stream, true);
format_val = snd_hdac_calc_stream_format(params->s_freq,
- params->ch, params->format, 32, 0);
+ 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);
@@ -190,8 +191,8 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
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, 24, 0);
+ 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);
@@ -262,23 +263,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
return 0;
}
-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)
{
@@ -326,6 +310,11 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
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)
@@ -564,6 +553,11 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
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);
}
@@ -649,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 = {
@@ -670,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",
@@ -677,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,
},
},
{
@@ -688,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,
},
},
{
@@ -699,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,
},
},
{
@@ -710,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,
},
},
{
@@ -721,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,
},
},
{
@@ -736,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,
},
},
{
@@ -751,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,
},
},
{
@@ -766,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,
},
},
@@ -949,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;
@@ -1062,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;
@@ -1165,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;
}
}
@@ -1173,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;
}
@@ -1232,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);
@@ -1256,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) {
@@ -1276,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 849410d0823e..eba20d37ba8c 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -17,13 +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-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
@@ -144,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_lib_info *linfo, int count);
+ 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);
@@ -172,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;
@@ -186,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,
@@ -214,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);
@@ -222,17 +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 9660ace379ab..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;
@@ -105,6 +118,8 @@ struct skl_sst {
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 {
@@ -182,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 b30bd384c8d3..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;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 2dbfb1b24ef4..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,22 +309,12 @@ 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 = in_rate * (mcfg->in_fmt->channels) *
- (mcfg->in_fmt->bit_depth >> 3) *
+ mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
+ in_fmt->channels * (in_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);
-
- mcfg->obs = out_rate * (mcfg->out_fmt->channels) *
- (mcfg->out_fmt->bit_depth >> 3) *
+ mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
+ out_fmt->channels * (out_fmt->bit_depth >> 3) *
multiplier;
}
@@ -551,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;
@@ -588,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);
@@ -614,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) {
@@ -623,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 */
@@ -645,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))
@@ -687,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.
@@ -726,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.
@@ -758,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;
}
@@ -772,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,
@@ -806,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;
@@ -985,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);
@@ -1019,6 +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;
+ struct skl_module_deferred_bind *modules, *tmp;
if (s_pipe->state == SKL_PIPE_INVALID)
return -EINVAL;
@@ -1027,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)
@@ -1042,6 +1144,11 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
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);
}
@@ -1083,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
@@ -1252,10 +1329,12 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
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:
@@ -1578,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},
};
@@ -1632,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;
}
}
@@ -1924,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;
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index fefab0e99a3b..cc64d6bdb4f6 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -257,6 +257,8 @@ struct skl_pipe_params {
snd_pcm_format_t format;
int link_index;
int stream;
+ unsigned int host_bps;
+ unsigned int link_bps;
};
struct skl_pipe {
@@ -334,17 +336,10 @@ struct skl_pipeline {
struct list_head node;
};
-#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_manifest {
- u32 lib_count;
- struct skl_lib_info lib[SKL_MAX_LIB];
+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)
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 0c57d4eaae3a..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);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 8e2878012d53..a454f6035f3e 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -56,6 +56,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];