clear-pkgs-linux-iot-lts2018/0343-ASoC-Intel-Skylake-Add...

254 lines
8.6 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Kareem,Shaik" <kareem.m.shaik@intel.com>
Date: Thu, 15 Jun 2017 13:40:04 +0530
Subject: [PATCH] ASoC: Intel: Skylake: Add support for always on CLK
configuration
For some platforms it is required that ADSP generate BCLK, Frame_sync
and MCLK regardless of whether audio stream is active or not. Clock
generation is controlled by ADSP Firmware, so driver can configure that
by sending DMA control IPC. The configuration for clock is prepared
using DMA control manifest data.
This patch prepares DMA control IPC by extracting specific ACPI NHLT
blob using DMA control manifest data and appending Firmware gateway
configuration to NHLT blob. Firmware Gateway configuration is available
in DMA control manifest data.
Finally DMA control IPC is sent to ADSP after firmware download is
completed and ADSP enters D0 state.
Change-Id: I65b090931c5ccaf1189c700975a1da6a772a44d8
Signed-off-by: Kareem,Shaik <kareem.m.shaik@intel.com>
---
sound/soc/intel/skylake/skl-messages.c | 92 ++++++++++++++++++++++++++
sound/soc/intel/skylake/skl-nhlt.c | 20 ++++++
sound/soc/intel/skylake/skl-pcm.c | 4 ++
sound/soc/intel/skylake/skl-topology.c | 11 +--
sound/soc/intel/skylake/skl-topology.h | 1 +
sound/soc/intel/skylake/skl.h | 3 +
6 files changed, 123 insertions(+), 8 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index b52f1c08d0a5..1fd9a3afe9a9 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -1169,6 +1169,10 @@ int skl_init_dsp(struct skl *skl)
dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
+ /* Set DMA clock controls */
+ ret = skl_dsp_set_dma_clk_controls(skl->skl_sst);
+ if (ret < 0)
+ return ret;
return 0;
free_core_state:
@@ -1291,6 +1295,9 @@ int skl_resume_dsp(struct skl *skl)
skl->cfg.astate_cfg);
}
return ret;
+
+ /* Set DMA clock controls */
+ return skl_dsp_set_dma_clk_controls(skl->skl_sst);
}
enum skl_bitdepth skl_get_bit_depth(int params)
@@ -1544,10 +1551,95 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl);
kfree(dma_ctrl);
+
return err;
}
EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control);
+static u32 skl_prepare_i2s_node_id(u32 instance, u8 dev_type,
+ u32 dir, u32 time_slot)
+{
+ union skl_connector_node_id node_id = {0};
+ union skl_ssp_dma_node ssp_node = {0};
+
+ node_id.node.dma_type = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
+ SKL_DMA_I2S_LINK_OUTPUT_CLASS :
+ SKL_DMA_I2S_LINK_INPUT_CLASS;
+ ssp_node.dma_node.time_slot_index = time_slot;
+ ssp_node.dma_node.i2s_instance = instance;
+ node_id.node.vindex = ssp_node.val;
+
+ return node_id.val;
+}
+
+int skl_dsp_set_dma_clk_controls(struct skl_sst *ctx)
+{
+ struct nhlt_specific_cfg *cfg = NULL;
+ struct skl *skl = get_skl_ctx(ctx->dev);
+ struct skl_dmactrl_config *dmactrl_cfg = &skl->cfg.dmactrl_cfg;
+ struct skl_dmctrl_hdr *hdr;
+ u8 *dma_ctrl_config;
+ void *i2s_config = NULL;
+ u32 i2s_config_size, node_id;
+ int i, ret = 0;
+
+ if (!skl->cfg.dmactrl_cfg.size)
+ return 0;
+
+ for (i = 0; i < SKL_MAX_DMACTRL; i++) {
+ hdr = &dmactrl_cfg->hdr[i];
+
+ /* get nhlt specific config info */
+ cfg = skl_get_nhlt_specific_cfg(skl, hdr->vbus_id,
+ NHLT_LINK_SSP, hdr->fmt,
+ hdr->ch, hdr->freq,
+ hdr->direction, NHLT_DEVICE_I2S);
+
+ if (cfg && hdr->data_size) {
+ print_hex_dump(KERN_DEBUG, "NHLT blob Info:",
+ DUMP_PREFIX_OFFSET, 8, 4,
+ cfg->caps, cfg->size, false);
+
+ i2s_config_size = cfg->size + hdr->data_size;
+ i2s_config = kzalloc(i2s_config_size, GFP_KERNEL);
+ if (!i2s_config)
+ return -ENOMEM;
+
+ /* copy blob */
+ memcpy(i2s_config, cfg->caps, cfg->size);
+
+ /* copy additional dma controls informatioin */
+ dma_ctrl_config = (u8 *)i2s_config + cfg->size;
+ memcpy(dma_ctrl_config, hdr->data, hdr->data_size);
+
+ print_hex_dump(KERN_DEBUG, "Blob + DMA Control Info:",
+ DUMP_PREFIX_OFFSET, 8, 4,
+ i2s_config, i2s_config_size, false);
+
+ /* get node id */
+ node_id = skl_prepare_i2s_node_id(hdr->vbus_id,
+ SKL_DEVICE_I2S,
+ hdr->direction,
+ hdr->tdm_slot);
+
+ ret = skl_dsp_set_dma_control(ctx, (u32 *)i2s_config,
+ i2s_config_size, node_id);
+
+ kfree(i2s_config);
+
+ if (ret < 0)
+ return ret;
+
+ } else {
+ dev_err(ctx->dev, "Failed to get NHLT config: vbusi_id=%d ch=%d fmt=%d s_rate=%d\n",
+ hdr->vbus_id, hdr->ch, hdr->fmt, hdr->freq);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 7063e8669763..b9bc3d12d0c0 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -149,6 +149,26 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
return false;
}
+struct nhlt_specific_cfg *
+skl_get_nhlt_specific_cfg(struct skl *skl, u32 instance, u8 link_type,
+ u8 s_fmt, u8 num_ch, u32 s_rate, u8 dir, u8 dev_type)
+{
+ struct nhlt_specific_cfg *cfg = NULL;
+ struct hdac_ext_bus *ebus = &skl->ebus;
+
+ /* update the blob based on virtual bus_id*/
+ if (!skl->nhlt_override) {
+ dev_warn(ebus_to_hbus(ebus)->dev, "Querying NHLT blob from ACPI NHLT table !!\n");
+ cfg = skl_get_ep_blob(skl, instance, link_type, s_fmt,
+ num_ch, s_rate, dir, dev_type);
+ } else {
+ dev_warn(ebus_to_hbus(ebus)->dev, "Querying NHLT blob from Debugfs!!\n");
+ cfg = skl_nhlt_get_debugfs_blob(skl->debugfs, link_type, instance, dir);
+ }
+
+ return cfg;
+}
+
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,
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 32c97d4b696d..9424a763c62c 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1854,6 +1854,10 @@ static int skl_platform_soc_probe(struct snd_soc_component *component)
dev_err(component->dev, "Failed to boot first fw: %d\n", ret);
return ret;
}
+
+ /* Set DMA clock controls */
+ skl_dsp_set_dma_clk_controls(skl->skl_sst);
+
skl_populate_modules(skl);
skl->skl_sst->update_d0i3c = skl_update_d0i3c;
skl_dsp_enable_notification(skl->skl_sst, false);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 87f204b77415..351897bb3967 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2548,18 +2548,13 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
mconfig->formats_config.caps = (u32 *) sdw_cfg;
return 0;
}
+
/* update the blob based on virtual bus_id*/
- if (!skl->nhlt_override) {
- cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
+ cfg = skl_get_nhlt_specific_cfg(skl, mconfig->vbus_id, link_type,
params->s_fmt, params->ch,
params->s_freq, params->stream,
dev_type);
- } else {
- dev_warn(dai->dev, "Querying NHLT blob from Debugfs!!!!\n");
- cfg = skl_nhlt_get_debugfs_blob(skl->debugfs,
- link_type, mconfig->vbus_id,
- params->stream);
- }
+
if (cfg) {
mconfig->formats_config.caps_size = cfg->size;
mconfig->formats_config.caps = (u32 *) &cfg->caps;
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 07d041fc8b72..8dbe73ee3d59 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -530,6 +530,7 @@ struct fw_ipc_data {
int skl_tplg_be_update_params(struct snd_soc_dai *dai,
struct skl_pipe_params *params);
+int skl_dsp_set_dma_clk_controls(struct skl_sst *ctx);
int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
u32 caps_size, u32 node_id);
void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 51cc193c3353..318b3c54c44e 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -172,6 +172,9 @@ 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 dev_type);
+struct nhlt_specific_cfg *
+skl_get_nhlt_specific_cfg(struct skl *skl, u32 instance, u8 link_type,
+ u8 s_fmt, u8 num_ch, u32 s_rate, u8 dir, u8 dev_type);
int skl_get_dmic_geo(struct skl *skl);
int skl_nhlt_update_topology_bin(struct skl *skl);
--
https://clearlinux.org