summaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/skylake
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 19:56:51 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 19:56:51 +0200
commit920f2ecdf6c3b3526f60fbd38c68597953cad3ee (patch)
tree18188922ba38a5c53ee8d17032eb5c46dffc7fa2 /sound/soc/intel/skylake
parentMerge branch 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/c... (diff)
parentALSA: hda - Fix unbalance of i915 module refcount (diff)
downloadlinux-920f2ecdf6c3b3526f60fbd38c68597953cad3ee.tar.xz
linux-920f2ecdf6c3b3526f60fbd38c68597953cad3ee.zip
Merge tag 'sound-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "This development cycle resulted in a fair amount of changes in both core and driver sides. The most significant change in ALSA core is about PCM. Also the support of of-graph card and the new DAPM widget for DSP are noteworthy changes in ASoC core. And there're lots of small changes splat over the tree, as you can see in diffstat. Below are a few highlights: ALSA core: - Removal of set_fs() hackery from PCM core stuff, and the code reorganization / optimization thereafter - Improved support of PCM ack ops, and a new ABI for improved control/status mmap handling - Lots of constifications in various codes ASoC core: - The support of of-graph card, which may work as a better generic device for a replacement of simple-card - New widget types intended mainly for use with DSPs ASoC drivers: - New drivers for Allwinner V3s SoCs - Ensonic ES8316 codec support - More Intel SKL and KBL works - More device support for Intel SST Atom (mostly for cheap tablets and 2-in-1 devices) - Support for Rockchip PDM controllers - Support for STM32 I2S and S/PDIF controllers - Support for ZTE AUD96P22 codecs HD-audio: - Support of new Realtek codecs (ALC215/ALC285/ALC289), more quirks for HP and Dell machines - A few more fixes for i915 component binding" * tag 'sound-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (418 commits) ALSA: hda - Fix unbalance of i915 module refcount ASoC: Intel: Skylake: Remove driver debugfs exit ASoC: Intel: Skylake: explicitly add the headers sst-dsp.h ALSA: hda/realtek - Remove GPIO_MASK ALSA: hda/realtek - Fix typo of pincfg for Dell quirk ALSA: pcm: add a documentation for tracepoints ALSA: atmel: ac97c: fix error return code in atmel_ac97c_probe() ALSA: x86: fix error return code in hdmi_lpe_audio_probe() ASoC: Intel: Skylake: Add support to read firmware registers ASoC: Intel: Skylake: Add sram address to sst_addr structure ASoC: Intel: Skylake: Debugfs facility to dump module config ASoC: Intel: Skylake: Add debugfs support ASoC: fix semicolon.cocci warnings ASoC: rt5645: Add quirk override by module option ASoC: rsnd: make arrays path and cmd_case static const ASoC: audio-graph-card: add widgets and routing for external amplifier support ASoC: audio-graph-card: update bindings for amplifier support ASoC: rt5665: calibration should be done before jack detection ASoC: rsnd: constify dev_pm_ops structures. ASoC: nau8825: change crosstalk-bypass property to bool type ...
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 */