summaryrefslogtreecommitdiff
path: root/sound/soc/intel/skylake
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2017-07-03 18:51:30 +0300
committerMark Brown <broonie@kernel.org>2017-07-03 18:51:30 +0300
commit2016d5ed401133539779d8a070abbe42fe9cb3da (patch)
tree96e1b8b348b2650345057fcaf7324983e6c2559f /sound/soc/intel/skylake
parent05325120861066e1e3e726eda54e429802725a64 (diff)
parent7d3d6e0645dd3689e625161b9e312108e66b2b51 (diff)
downloadlinux-2016d5ed401133539779d8a070abbe42fe9cb3da.tar.xz
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
Diffstat (limited to 'sound/soc/intel/skylake')
-rw-r--r--sound/soc/intel/skylake/Makefile4
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c4
-rw-r--r--sound/soc/intel/skylake/skl-debug.c261
-rw-r--r--sound/soc/intel/skylake/skl-messages.c31
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst.c5
-rw-r--r--sound/soc/intel/skylake/skl-topology.c187
-rw-r--r--sound/soc/intel/skylake/skl-topology.h21
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h2
-rw-r--r--sound/soc/intel/skylake/skl.c114
-rw-r--r--sound/soc/intel/skylake/skl.h23
11 files changed, 638 insertions, 20 deletions
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index 60fbc9bbe473..e7d77722d560 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -1,6 +1,10 @@
snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \
skl-topology.o
+ifdef CONFIG_DEBUG_FS
+ snd-soc-skl-objs += skl-debug.o
+endif
+
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index f5e7dbb1ba39..cf11b84888b9 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -573,6 +573,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst->fw_ops = bxt_fw_ops;
sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base;
+ sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE;
+ sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE;
+ sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
+ sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
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);
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
new file mode 100644
index 000000000000..dc20d91f62e6
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-debug.c
@@ -0,0 +1,261 @@
+/*
+ * skl-debug.c - Debugfs for skl driver
+ *
+ * Copyright (C) 2016-17 Intel Corp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/pci.h>
+#include <linux/debugfs.h>
+#include "skl.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+#include "skl-tplg-interface.h"
+#include "skl-topology.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+
+#define MOD_BUF PAGE_SIZE
+#define FW_REG_BUF PAGE_SIZE
+#define FW_REG_SIZE 0x60
+
+struct skl_debug {
+ struct skl *skl;
+ struct device *dev;
+
+ struct dentry *fs;
+ struct dentry *modules;
+ u8 fw_read_buff[FW_REG_BUF];
+};
+
+static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
+ int max_pin, ssize_t size, bool direction)
+{
+ int i;
+ ssize_t ret = 0;
+
+ for (i = 0; i < max_pin; i++)
+ ret += snprintf(buf + size, MOD_BUF - size,
+ "%s %d\n\tModule %d\n\tInstance %d\n\t"
+ "In-used %s\n\tType %s\n"
+ "\tState %d\n\tIndex %d\n",
+ direction ? "Input Pin:" : "Output Pin:",
+ i, m_pin[i].id.module_id,
+ m_pin[i].id.instance_id,
+ m_pin[i].in_use ? "Used" : "Unused",
+ m_pin[i].is_dynamic ? "Dynamic" : "Static",
+ m_pin[i].pin_state, i);
+ return ret;
+}
+
+static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf,
+ ssize_t size, bool direction)
+{
+ return snprintf(buf + size, MOD_BUF - size,
+ "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t"
+ "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t"
+ "Sample Type %d\n\tCh Map %#x\n",
+ direction ? "Input Format:" : "Output Format:",
+ fmt->channels, fmt->s_freq, fmt->bit_depth,
+ fmt->valid_bit_depth, fmt->ch_cfg,
+ fmt->interleaving_style, fmt->sample_type,
+ fmt->ch_map);
+}
+
+static ssize_t module_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct skl_module_cfg *mconfig = file->private_data;
+ char *buf;
+ ssize_t ret;
+
+ buf = kzalloc(MOD_BUF, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
+ "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid,
+ mconfig->id.module_id, mconfig->id.instance_id,
+ mconfig->id.pvt_id);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n",
+ mconfig->mcps, mconfig->ibs, mconfig->obs);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Module data:\n\tCore %d\n\tIn queue %d\n\t"
+ "Out queue %d\n\tType %s\n",
+ mconfig->core_id, mconfig->max_in_queue,
+ mconfig->max_out_queue,
+ mconfig->is_loadable ? "loadable" : "inbuilt");
+
+ ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true);
+ ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Fixup:\n\tParams %#x\n\tConverter %#x\n",
+ mconfig->params_fixup, mconfig->converter);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n",
+ mconfig->dev_type, mconfig->vbus_id,
+ mconfig->hw_conn_type, mconfig->time_slot);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t"
+ "Pages %#x\n", mconfig->pipe->ppl_id,
+ mconfig->pipe->pipe_priority, mconfig->pipe->conn_type,
+ mconfig->pipe->memory_pages);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n",
+ mconfig->pipe->p_params->host_dma_id,
+ mconfig->pipe->p_params->link_dma_id);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n",
+ mconfig->pipe->p_params->ch,
+ mconfig->pipe->p_params->s_freq,
+ mconfig->pipe->p_params->s_fmt);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "\tLink %#x\n\tStream %#x\n",
+ mconfig->pipe->p_params->linktype,
+ mconfig->pipe->p_params->stream);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "\tState %d\n\tPassthru %s\n",
+ mconfig->pipe->state,
+ mconfig->pipe->passthru ? "true" : "false");
+
+ ret += skl_print_pins(mconfig->m_in_pin, buf,
+ mconfig->max_in_queue, ret, true);
+ ret += skl_print_pins(mconfig->m_out_pin, buf,
+ mconfig->max_out_queue, ret, false);
+
+ ret += snprintf(buf + ret, MOD_BUF - ret,
+ "Other:\n\tDomain %d\n\tHomogenous Input %s\n\t"
+ "Homogenous Output %s\n\tIn Queue Mask %d\n\t"
+ "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
+ "Module Type %d\n\tModule State %d\n",
+ mconfig->domain,
+ mconfig->homogenous_inputs ? "true" : "false",
+ mconfig->homogenous_outputs ? "true" : "false",
+ mconfig->in_queue_mask, mconfig->out_queue_mask,
+ mconfig->dma_id, mconfig->mem_pages, mconfig->m_state,
+ mconfig->m_type);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations mcfg_fops = {
+ .open = simple_open,
+ .read = module_read,
+ .llseek = default_llseek,
+};
+
+
+void skl_debug_init_module(struct skl_debug *d,
+ struct snd_soc_dapm_widget *w,
+ struct skl_module_cfg *mconfig)
+{
+ if (!debugfs_create_file(w->name, 0444,
+ d->modules, mconfig,
+ &mcfg_fops))
+ dev_err(d->dev, "%s: module debugfs init failed\n", w->name);
+}
+
+static ssize_t fw_softreg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct skl_debug *d = file->private_data;
+ struct sst_dsp *sst = d->skl->skl_sst->dsp;
+ size_t w0_stat_sz = sst->addr.w0_stat_sz;
+ void __iomem *in_base = sst->mailbox.in_base;
+ void __iomem *fw_reg_addr;
+ unsigned int offset;
+ char *tmp;
+ ssize_t ret = 0;
+
+ tmp = kzalloc(FW_REG_BUF, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ fw_reg_addr = in_base - w0_stat_sz;
+ memset(d->fw_read_buff, 0, FW_REG_BUF);
+
+ if (w0_stat_sz > 0)
+ __iowrite32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2);
+
+ for (offset = 0; offset < FW_REG_SIZE; offset += 16) {
+ ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
+ hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4,
+ tmp + ret, FW_REG_BUF - ret, 0);
+ ret += strlen(tmp + ret);
+
+ /* print newline for each offset */
+ if (FW_REG_BUF - ret > 0)
+ tmp[ret++] = '\n';
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret);
+ kfree(tmp);
+
+ return ret;
+}
+
+static const struct file_operations soft_regs_ctrl_fops = {
+ .open = simple_open,
+ .read = fw_softreg_read,
+ .llseek = default_llseek,
+};
+
+struct skl_debug *skl_debugfs_init(struct skl *skl)
+{
+ struct skl_debug *d;
+
+ d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL);
+ if (!d)
+ return NULL;
+
+ /* create the debugfs dir with platform component's debugfs as parent */
+ d->fs = debugfs_create_dir("dsp",
+ skl->platform->component.debugfs_root);
+ if (IS_ERR(d->fs) || !d->fs) {
+ dev_err(&skl->pci->dev, "debugfs root creation failed\n");
+ return NULL;
+ }
+
+ d->skl = skl;
+ d->dev = &skl->pci->dev;
+
+ /* now create the module dir */
+ d->modules = debugfs_create_dir("modules", d->fs);
+ if (IS_ERR(d->modules) || !d->modules) {
+ dev_err(&skl->pci->dev, "modules debugfs create failed\n");
+ goto err;
+ }
+
+ if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d,
+ &soft_regs_ctrl_fops)) {
+ dev_err(d->dev, "fw soft regs control debugfs init failed\n");
+ goto err;
+ }
+
+ return d;
+
+err:
+ debugfs_remove_recursive(d->fs);
+ return NULL;
+}
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index ab1adc0c9cc3..eca85827dbd2 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -507,6 +507,8 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_cpr_cfg *cpr_mconfig)
{
+ u32 dma_io_buf;
+
cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) {
@@ -514,10 +516,29 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
return;
}
- if (SKL_CONN_SOURCE == mconfig->hw_conn_type)
- cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
- else
- cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
+ switch (mconfig->hw_conn_type) {
+ case SKL_CONN_SOURCE:
+ if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
+ dma_io_buf = mconfig->ibs;
+ else
+ dma_io_buf = mconfig->obs;
+ break;
+
+ case SKL_CONN_SINK:
+ if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
+ dma_io_buf = mconfig->obs;
+ else
+ dma_io_buf = mconfig->ibs;
+ break;
+
+ default:
+ dev_warn(ctx->dev, "wrong connection type: %d\n",
+ mconfig->hw_conn_type);
+ return;
+ }
+
+ cpr_mconfig->gtw_cfg.dma_buffer_size =
+ mconfig->dma_buffer_size * dma_io_buf;
cpr_mconfig->cpr_feature_mask = 0;
cpr_mconfig->gtw_cfg.config_length = 0;
@@ -707,6 +728,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
return param_size;
case SKL_MODULE_TYPE_BASE_OUTFMT:
+ case SKL_MODULE_TYPE_MIC_SELECT:
case SKL_MODULE_TYPE_KPB:
return sizeof(struct skl_base_outfmt_cfg);
@@ -761,6 +783,7 @@ static int skl_set_module_format(struct skl_sst *ctx,
break;
case SKL_MODULE_TYPE_BASE_OUTFMT:
+ case SKL_MODULE_TYPE_MIC_SELECT:
case SKL_MODULE_TYPE_KPB:
skl_set_base_outfmt_format(ctx, module_config, *param_data);
break;
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index e91bbcffc856..0ebea34a4988 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1249,12 +1249,16 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
pm_runtime_get_sync(platform->dev);
if ((ebus_to_hbus(ebus))->ppcap) {
+ skl->platform = platform;
+
+ /* init debugfs */
+ skl->debugfs = skl_debugfs_init(skl);
+
ret = skl_tplg_init(platform, ebus);
if (ret < 0) {
dev_err(platform->dev, "Failed to init topology!\n");
return ret;
}
- skl->platform = platform;
/* load the firmwares, since all is set */
ops = skl_get_dsp_ops(skl->pci->device);
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 155e456b7a3a..aba9ea11ac74 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -553,6 +553,11 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst = skl->dsp;
sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base;
+ sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE;
+ sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE;
+ sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
+ sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
+
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);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 64a0f8ed33e1..68c3f121efc3 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -36,6 +36,19 @@
#define SKL_IN_DIR_BIT_MASK BIT(0)
#define SKL_PIN_COUNT_MASK GENMASK(7, 4)
+static const int mic_mono_list[] = {
+0, 1, 2, 3,
+};
+static const int mic_stereo_list[][SKL_CH_STEREO] = {
+{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
+};
+static const int mic_trio_list[][SKL_CH_TRIO] = {
+{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
+};
+static const int mic_quatro_list[][SKL_CH_QUATRO] = {
+{0, 1, 2, 3},
+};
+
void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
{
struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3;
@@ -1314,6 +1327,111 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
return 0;
}
+static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct skl_module_cfg *mconfig = w->priv;
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+ u32 ch_type = *((u32 *)ec->dobj.private);
+
+ if (mconfig->dmic_ch_type == ch_type)
+ ucontrol->value.enumerated.item[0] =
+ mconfig->dmic_ch_combo_index;
+ else
+ ucontrol->value.enumerated.item[0] = 0;
+
+ return 0;
+}
+
+static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
+ struct skl_mic_sel_config *mic_cfg, struct device *dev)
+{
+ struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
+
+ sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
+ sp_cfg->set_params = SKL_PARAM_SET;
+ sp_cfg->param_id = 0x00;
+ if (!sp_cfg->caps) {
+ sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
+ if (!sp_cfg->caps)
+ return -ENOMEM;
+ }
+
+ mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
+ mic_cfg->flags = 0;
+ memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
+
+ return 0;
+}
+
+static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct skl_module_cfg *mconfig = w->priv;
+ struct skl_mic_sel_config mic_cfg = {0};
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+ u32 ch_type = *((u32 *)ec->dobj.private);
+ const int *list;
+ u8 in_ch, out_ch, index;
+
+ mconfig->dmic_ch_type = ch_type;
+ mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
+
+ /* enum control index 0 is INVALID, so no channels to be set */
+ if (mconfig->dmic_ch_combo_index == 0)
+ return 0;
+
+ /* No valid channel selection map for index 0, so offset by 1 */
+ index = mconfig->dmic_ch_combo_index - 1;
+
+ switch (ch_type) {
+ case SKL_CH_MONO:
+ if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
+ return -EINVAL;
+
+ list = &mic_mono_list[index];
+ break;
+
+ case SKL_CH_STEREO:
+ if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
+ return -EINVAL;
+
+ list = mic_stereo_list[index];
+ break;
+
+ case SKL_CH_TRIO:
+ if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
+ return -EINVAL;
+
+ list = mic_trio_list[index];
+ break;
+
+ case SKL_CH_QUATRO:
+ if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
+ return -EINVAL;
+
+ list = mic_quatro_list[index];
+ break;
+
+ default:
+ dev_err(w->dapm->dev,
+ "Invalid channel %d for mic_select module\n",
+ ch_type);
+ return -EINVAL;
+
+ }
+
+ /* channel type enum map to number of chanels for that type */
+ for (out_ch = 0; out_ch < ch_type; out_ch++) {
+ in_ch = list[out_ch];
+ mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
+ }
+
+ return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
+}
+
/*
* Fill the dma id for host and link. In case of passthrough
* pipeline, this will both host and link in the same
@@ -1666,6 +1784,14 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
skl_tplg_tlv_control_set},
};
+static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
+ {
+ .id = SKL_CONTROL_TYPE_MIC_SELECT,
+ .get = skl_tplg_mic_control_get,
+ .put = skl_tplg_mic_control_set,
+ },
+};
+
static int skl_tplg_fill_pipe_tkn(struct device *dev,
struct skl_pipe *pipe, u32 tkn,
u32 tkn_val)
@@ -1995,7 +2121,7 @@ static int skl_tplg_get_token(struct device *dev,
mconfig->converter = tkn_elem->value;
break;
- case SKL_TKL_U32_D0I3_CAPS:
+ case SKL_TKN_U32_D0I3_CAPS:
mconfig->d0i3_caps = tkn_elem->value;
break;
@@ -2070,12 +2196,26 @@ static int skl_tplg_get_token(struct device *dev,
break;
+ case SKL_TKN_U32_CAPS_SET_PARAMS:
+ mconfig->formats_config.set_params =
+ tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_CAPS_PARAMS_ID:
+ mconfig->formats_config.param_id =
+ tkn_elem->value;
+ break;
+
case SKL_TKN_U32_PROC_DOMAIN:
mconfig->domain =
tkn_elem->value;
break;
+ case SKL_TKN_U32_DMA_BUF_SIZE:
+ mconfig->dma_buffer_size = tkn_elem->value;
+ break;
+
case SKL_TKN_U8_IN_PIN_TYPE:
case SKL_TKN_U8_OUT_PIN_TYPE:
case SKL_TKN_U8_CONN_TYPE:
@@ -2147,7 +2287,7 @@ static int skl_tplg_get_tokens(struct device *dev,
tuple_size += tkn_count * sizeof(*tkn_elem);
}
- return 0;
+ return off;
}
/*
@@ -2198,10 +2338,11 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
num_blocks = ret;
off += array->size;
- array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off);
-
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
while (num_blocks > 0) {
+ array = (struct snd_soc_tplg_vendor_array *)
+ (tplg_w->priv.data + off);
+
ret = skl_tplg_get_desc_blocks(dev, array);
if (ret < 0)
@@ -2237,7 +2378,9 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
memcpy(mconfig->formats_config.caps, data,
mconfig->formats_config.caps_size);
--num_blocks;
+ ret = mconfig->formats_config.caps_size;
}
+ off += ret;
}
return 0;
@@ -2329,6 +2472,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
if (ret < 0)
return ret;
+
+ skl_debug_init_module(skl->debugfs, w, mconfig);
+
bind_event:
if (tplg_w->event_type == 0) {
dev_dbg(bus->dev, "ASoC: No event handler required\n");
@@ -2377,14 +2523,34 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
return 0;
}
+static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
+ struct snd_soc_tplg_enum_control *ec)
+{
+
+ void *data;
+
+ if (ec->priv.size) {
+ data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ memcpy(data, ec->priv.data, ec->priv.size);
+ se->dobj.private = data;
+ }
+
+ return 0;
+
+}
+
static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
struct snd_kcontrol_new *kctl,
struct snd_soc_tplg_ctl_hdr *hdr)
{
struct soc_bytes_ext *sb;
struct snd_soc_tplg_bytes_control *tplg_bc;
+ struct snd_soc_tplg_enum_control *tplg_ec;
struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct soc_enum *se;
switch (hdr->ops.info) {
case SND_SOC_TPLG_CTL_BYTES:
@@ -2398,6 +2564,17 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
}
break;
+ case SND_SOC_TPLG_CTL_ENUM:
+ tplg_ec = container_of(hdr,
+ struct snd_soc_tplg_enum_control, hdr);
+ if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
+ se = (struct soc_enum *)kctl->private_value;
+ if (tplg_ec->priv.size)
+ return skl_init_enum_data(bus->dev, se,
+ tplg_ec);
+ }
+ break;
+
default:
dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
hdr->ops.get, hdr->ops.put, hdr->ops.info);
@@ -2626,6 +2803,8 @@ static struct snd_soc_tplg_ops skl_tplg_ops = {
.control_load = skl_tplg_control_load,
.bytes_ext_ops = skl_tlv_ops,
.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
+ .io_ops = skl_tplg_kcontrol_ops,
+ .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
.manifest = skl_manifest_load,
};
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index cc64d6bdb4f6..c25e8868b84e 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -39,6 +39,11 @@
#define MODULE_MAX_IN_PINS 8
#define MODULE_MAX_OUT_PINS 8
+#define SKL_MIC_CH_SUPPORT 4
+#define SKL_MIC_MAX_CH_SUPPORT 8
+#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF
+#define SKL_MIC_SEL_SWITCH 0x3
+
enum skl_channel_index {
SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1,
@@ -309,11 +314,14 @@ struct skl_module_cfg {
u8 dev_type;
u8 dma_id;
u8 time_slot;
+ u8 dmic_ch_combo_index;
+ u32 dmic_ch_type;
u32 params_fixup;
u32 converter;
u32 vbus_id;
u32 mem_pages;
enum d0i3_capability d0i3_caps;
+ u32 dma_buffer_size; /* in milli seconds */
struct skl_module_pin *m_in_pin;
struct skl_module_pin *m_out_pin;
enum skl_module_type m_type;
@@ -342,6 +350,19 @@ struct skl_module_deferred_bind {
struct list_head node;
};
+struct skl_mic_sel_config {
+ u16 mic_switch;
+ u16 flags;
+ u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT];
+} __packed;
+
+enum skl_channel {
+ SKL_CH_MONO = 1,
+ SKL_CH_STEREO = 2,
+ SKL_CH_TRIO = 3,
+ SKL_CH_QUATRO = 4,
+};
+
static inline struct skl *get_skl_ctx(struct device *dev)
{
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index 7a2febf99019..f8d1749a2e0c 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -24,6 +24,7 @@
* SST types start at higher to avoid any overlapping in future
*/
#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
+#define SKL_CONTROL_TYPE_MIC_SELECT 0x102
#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
#define MAX_IN_QUEUE 8
@@ -82,6 +83,7 @@ enum skl_module_type {
SKL_MODULE_TYPE_ALGO,
SKL_MODULE_TYPE_BASE_OUTFMT,
SKL_MODULE_TYPE_KPB,
+ SKL_MODULE_TYPE_MIC_SELECT,
};
enum skl_core_affinity {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 4c9b5781282b..334917ee41cf 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -866,6 +866,7 @@ static void skl_remove(struct pci_dev *pci)
/* codec removal, invoke bus_device_remove */
snd_hdac_ext_bus_device_remove(ebus);
+ skl->debugfs = NULL;
skl_platform_unregister(&pci->dev);
skl_free_dsp(skl);
skl_machine_device_unregister(skl);
@@ -876,29 +877,120 @@ static void skl_remove(struct pci_dev *pci)
dev_set_drvdata(&pci->dev, NULL);
}
+static struct sst_codecs skl_codecs = {
+ .num_codecs = 1,
+ .codecs = {"NAU88L25"}
+};
+
+static struct sst_codecs kbl_codecs = {
+ .num_codecs = 1,
+ .codecs = {"NAU88L25"}
+};
+
+static struct sst_codecs bxt_codecs = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
+static struct sst_codecs kbl_poppy_codecs = {
+ .num_codecs = 1,
+ .codecs = {"10EC5663"}
+};
+
+static struct sst_codecs kbl_5663_5514_codecs = {
+ .num_codecs = 2,
+ .codecs = {"10EC5663", "10EC5514"}
+};
+
+
static struct sst_acpi_mach sst_skl_devdata[] = {
- { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
- { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin",
- NULL, NULL, &skl_dmic_data },
- { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin",
- NULL, NULL, &skl_dmic_data },
+ {
+ .id = "INT343A",
+ .drv_name = "skl_alc286s_i2s",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ },
+ {
+ .id = "INT343B",
+ .drv_name = "skl_n88l25_s4567",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &skl_codecs,
+ .pdata = &skl_dmic_data
+ },
+ {
+ .id = "MX98357A",
+ .drv_name = "skl_n88l25_m98357a",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &skl_codecs,
+ .pdata = &skl_dmic_data
+ },
{}
};
static struct sst_acpi_mach sst_bxtp_devdata[] = {
- { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
- { "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
+ {
+ .id = "INT343A",
+ .drv_name = "bxt_alc298s_i2s",
+ .fw_filename = "intel/dsp_fw_bxtn.bin",
+ },
+ {
+ .id = "DLGS7219",
+ .drv_name = "bxt_da7219_max98357a_i2s",
+ .fw_filename = "intel/dsp_fw_bxtn.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &bxt_codecs,
+ },
};
static struct sst_acpi_mach sst_kbl_devdata[] = {
- { "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL },
- { "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
- { "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
+ {
+ .id = "INT343A",
+ .drv_name = "kbl_alc286s_i2s",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
+ {
+ .id = "INT343B",
+ .drv_name = "kbl_n88l25_s4567",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &kbl_codecs,
+ .pdata = &skl_dmic_data
+ },
+ {
+ .id = "MX98357A",
+ .drv_name = "kbl_n88l25_m98357a",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &kbl_codecs,
+ .pdata = &skl_dmic_data
+ },
+ {
+ .id = "MX98927",
+ .drv_name = "kbl_r5514_5663_max",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &kbl_5663_5514_codecs,
+ .pdata = &skl_dmic_data
+ },
+ {
+ .id = "MX98927",
+ .drv_name = "kbl_rt5663_m98927",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = sst_acpi_codec_list,
+ .quirk_data = &kbl_poppy_codecs,
+ .pdata = &skl_dmic_data
+ },
+
{}
};
static struct sst_acpi_mach sst_glk_devdata[] = {
- { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL },
+ {
+ .id = "INT343A",
+ .drv_name = "glk_alc298s_i2s",
+ .fw_filename = "intel/dsp_fw_glk.bin",
+ },
};
/* PCI IDs */
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 2a630fcb7f08..a6b134b4c037 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -23,6 +23,7 @@
#include <sound/hda_register.h>
#include <sound/hdaudio_ext.h>
+#include <sound/soc.h>
#include "skl-nhlt.h"
#define SKL_SUSPEND_DELAY 2000
@@ -42,6 +43,8 @@ struct skl_dsp_resource {
u32 mem;
};
+struct skl_debug;
+
struct skl {
struct hdac_ext_bus ebus;
struct pci_dev *pci;
@@ -66,6 +69,8 @@ struct skl {
int supend_active;
struct work_struct probe_work;
+
+ struct skl_debug *debugfs;
};
#define skl_to_ebus(s) (&(s)->ebus)
@@ -116,4 +121,22 @@ 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);
+struct skl_module_cfg;
+
+#ifdef CONFIG_DEBUG_FS
+struct skl_debug *skl_debugfs_init(struct skl *skl);
+void skl_debug_init_module(struct skl_debug *d,
+ struct snd_soc_dapm_widget *w,
+ struct skl_module_cfg *mconfig);
+#else
+static inline struct skl_debug *skl_debugfs_init(struct skl *skl)
+{
+ return NULL;
+}
+static inline void skl_debug_init_module(struct skl_debug *d,
+ struct snd_soc_dapm_widget *w,
+ struct skl_module_cfg *mconfig)
+{}
+#endif
+
#endif /* __SOUND_SOC_SKL_H */