summaryrefslogtreecommitdiffstats
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.c174
-rw-r--r--sound/soc/intel/skylake/skl-messages.c23
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c65
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c289
-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.h22
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c140
-rw-r--r--sound/soc/intel/skylake/skl-sst.c178
-rw-r--r--sound/soc/intel/skylake/skl-topology.c344
-rw-r--r--sound/soc/intel/skylake/skl-topology.h14
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h12
-rw-r--r--sound/soc/intel/skylake/skl.c14
-rw-r--r--sound/soc/intel/skylake/skl.h6
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 */
OpenPOWER on IntegriCloud