summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/intel/Kconfig17
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c67
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c368
-rw-r--r--sound/soc/intel/boards/skl_rt286.c55
-rw-r--r--sound/soc/intel/common/Makefile3
-rw-r--r--sound/soc/intel/common/sst-acpi.c41
-rw-r--r--sound/soc/intel/common/sst-acpi.h33
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h8
-rw-r--r--sound/soc/intel/common/sst-firmware.c4
-rw-r--r--sound/soc/intel/common/sst-match-acpi.c43
-rw-r--r--sound/soc/intel/haswell/sst-haswell-dsp.c2
-rw-r--r--sound/soc/intel/skylake/skl-messages.c191
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c19
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c185
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c20
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h3
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c2
-rw-r--r--sound/soc/intel/skylake/skl-sst.c42
-rw-r--r--sound/soc/intel/skylake/skl-topology.c389
-rw-r--r--sound/soc/intel/skylake/skl-topology.h35
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h90
-rw-r--r--sound/soc/intel/skylake/skl.c134
-rw-r--r--sound/soc/intel/skylake/skl.h4
24 files changed, 1158 insertions, 599 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 7b778ab85f8b..aee2a5c75e0d 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -24,6 +24,7 @@ config SND_SST_IPC_PCI
config SND_SST_IPC_ACPI
tristate
select SND_SST_IPC
+ select SND_SOC_INTEL_SST
depends on ACPI
config SND_SOC_INTEL_SST
@@ -144,7 +145,7 @@ config SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
- depends on X86 && ACPI
+ depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
@@ -154,3 +155,17 @@ config SND_SOC_INTEL_SKL_RT286_MACH
with RT286 I2S audio codec.
Say Y if you have such a device
If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
+ tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_NAU8825
+ select SND_SOC_SSM4567
+ select SND_SOC_DMIC
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for NAU88L25 + SSM4567.
+ Say Y if you have such a device
+ If unsure select "N".
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index bb19b5801466..f3d109eb3800 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -40,18 +40,9 @@
#include <acpi/acpi_bus.h>
#include "../sst-mfld-platform.h"
#include "../../common/sst-dsp.h"
+#include "../../common/sst-acpi.h"
#include "sst.h"
-struct sst_machines {
- char *codec_id;
- char board[32];
- char machine[32];
- void (*machine_quirk)(void);
- char firmware[FW_NAME_SIZE];
- struct sst_platform_info *pdata;
-
-};
-
/* LPE viewpoint addresses */
#define SST_BYT_IRAM_PHY_START 0xff2c0000
#define SST_BYT_IRAM_PHY_END 0xff2d4000
@@ -223,37 +214,16 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
return 0;
}
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
-static struct sst_machines *sst_acpi_find_machine(
- struct sst_machines *machines)
-{
- struct sst_machines *mach;
- bool found = false;
-
- for (mach = machines; mach->codec_id; mach++)
- if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
- sst_acpi_mach_match,
- &found, NULL)) && found)
- return mach;
-
- return NULL;
-}
-
static int sst_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0;
struct intel_sst_drv *ctx;
const struct acpi_device_id *id;
- struct sst_machines *mach;
+ struct sst_acpi_mach *mach;
struct platform_device *mdev;
struct platform_device *plat_dev;
+ struct sst_platform_info *pdata;
unsigned int dev_id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
@@ -261,12 +231,13 @@ static int sst_acpi_probe(struct platform_device *pdev)
return -ENODEV;
dev_dbg(dev, "for %s", id->id);
- mach = (struct sst_machines *)id->driver_data;
+ mach = (struct sst_acpi_mach *)id->driver_data;
mach = sst_acpi_find_machine(mach);
if (mach == NULL) {
dev_err(dev, "No matching machine driver found\n");
return -ENODEV;
}
+ pdata = mach->pdata;
ret = kstrtouint(id->id, 16, &dev_id);
if (ret < 0) {
@@ -276,16 +247,16 @@ static int sst_acpi_probe(struct platform_device *pdev)
dev_dbg(dev, "ACPI device id: %x\n", dev_id);
- plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+ plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0);
if (IS_ERR(plat_dev)) {
- dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+ dev_err(dev, "Failed to create machine device: %s\n", pdata->platform);
return PTR_ERR(plat_dev);
}
/* Create platform device for sst machine driver */
- mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
+ mdev = platform_device_register_data(dev, mach->drv_name, -1, NULL, 0);
if (IS_ERR(mdev)) {
- dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+ dev_err(dev, "Failed to create machine device: %s\n", mach->drv_name);
return PTR_ERR(mdev);
}
@@ -294,8 +265,8 @@ static int sst_acpi_probe(struct platform_device *pdev)
return ret;
/* Fill sst platform data */
- ctx->pdata = mach->pdata;
- strcpy(ctx->firmware_name, mach->firmware);
+ ctx->pdata = pdata;
+ strcpy(ctx->firmware_name, mach->fw_filename);
ret = sst_platform_get_resources(ctx);
if (ret)
@@ -342,22 +313,22 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0;
}
-static struct sst_machines sst_acpi_bytcr[] = {
- {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
+static struct sst_acpi_mach sst_acpi_bytcr[] = {
+ {"10EC5640", "bytt100_rt5640", "intel/fw_sst_0f28.bin", "T100", NULL,
&byt_rvp_platform_data },
{},
};
/* Cherryview-based platforms: CherryTrail and Braswell */
-static struct sst_machines sst_acpi_chv[] = {
- {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
+static struct sst_acpi_mach sst_acpi_chv[] = {
+ {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+ &chv_platform_data },
+ {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+ {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+ {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL,
- "intel/fw_sst_22a8.bin", &chv_platform_data },
{},
};
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 371c4565cad8..a59f76277cee 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -7,6 +7,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
snd-soc-skl_rt286-objs := skl_rt286.o
+snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -17,3 +18,4 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
new file mode 100644
index 000000000000..3f5a96b585b8
--- /dev/null
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -0,0 +1,368 @@
+/*
+ * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+ int i;
+
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd;
+
+ rtd = card->rtd + i;
+ if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+ strlen(SKL_NUVOTON_CODEC_DAI)))
+ return rtd->codec_dai;
+ }
+
+ return NULL;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Left Speaker"),
+ SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = skl_get_codec_dai(card);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ }
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Left Speaker", NULL),
+ SND_SOC_DAPM_SPK("Right Speaker", NULL),
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route skylake_map[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ {"Headphone Jack", NULL, "HPOL"},
+ {"Headphone Jack", NULL, "HPOR"},
+
+ /* speaker */
+ {"Left Speaker", NULL, "Left OUT"},
+ {"Right Speaker", NULL, "Right OUT"},
+
+ /* other jacks */
+ {"MIC", NULL, "Headset Mic"},
+ {"DMIC AIF", NULL, "SoC DMIC"},
+
+ /* CODEC BE connections */
+ { "Left Playback", NULL, "ssp0 Tx"},
+ { "Right Playback", NULL, "ssp0 Tx"},
+ { "ssp0 Tx", NULL, "codec0_out"},
+
+ { "AIF1 Playback", NULL, "ssp1 Tx"},
+ { "ssp1 Tx", NULL, "codec1_out"},
+
+ { "codec0_in", NULL, "ssp1 Rx" },
+ { "ssp1 Rx", NULL, "AIF1 Capture" },
+
+ /* DMIC */
+ { "dmic01_hifi", NULL, "DMIC01 Rx" },
+ { "DMIC01 Rx", NULL, "Capture" },
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
+ {
+ .dev_name = "i2c-INT343B:00",
+ .name_prefix = "Left",
+ },
+ {
+ .dev_name = "i2c-INT343B:01",
+ .name_prefix = "Right",
+ },
+};
+
+static struct snd_soc_dai_link_component ssm4567_codec_components[] = {
+ { /* Left */
+ .name = "i2c-INT343B:00",
+ .dai_name = SKL_SSM_CODEC_DAI,
+ },
+ { /* Right */
+ .name = "i2c-INT343B:01",
+ .dai_name = SKL_SSM_CODEC_DAI,
+ },
+};
+
+static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ /* Slot 1 for left */
+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ /* Slot 2 for right */
+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /*
+ * 4 buttons here map to the google Reference headset
+ * The use of these buttons can be decided by the user space.
+ */
+ ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+ NULL, 0);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ nau8825_enable_jack_detect(codec, &skylake_headset);
+
+ return ret;
+}
+
+static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+ .hw_params = skylake_nau8825_hw_params,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "Skl Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ },
+ {
+ .name = "Skl Audio Capture Port",
+ .stream_name = "Audio Record",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "Skl Audio Reference cap",
+ .stream_name = "refcap",
+ .cpu_dai_name = "Reference Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "SSP0-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP0 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codecs = ssm4567_codec_components,
+ .num_codecs = ARRAY_SIZE(ssm4567_codec_components),
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .init = skylake_ssm4567_codec_init,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = skylake_ssp_fixup,
+ .dpcm_playback = 1,
+ },
+ {
+ /* SSP1 - Codec */
+ .name = "SSP1-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP1 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10508825:00",
+ .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+ .init = skylake_nau8825_codec_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = skylake_ssp_fixup,
+ .ops = &skylake_nau8825_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "dmic01",
+ .be_id = 1,
+ .cpu_dai_name = "DMIC01 Pin",
+ .codec_name = "dmic-codec",
+ .codec_dai_name = "dmic-hifi",
+ .platform_name = "0000:00:1f.3",
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ },
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+ .name = "sklnau8825adi",
+ .owner = THIS_MODULE,
+ .dai_link = skylake_dais,
+ .num_links = ARRAY_SIZE(skylake_dais),
+ .controls = skylake_controls,
+ .num_controls = ARRAY_SIZE(skylake_controls),
+ .dapm_widgets = skylake_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+ .dapm_routes = skylake_map,
+ .num_dapm_routes = ARRAY_SIZE(skylake_map),
+ .codec_conf = ssm4567_codec_conf,
+ .num_configs = ARRAY_SIZE(ssm4567_codec_conf),
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+ skylake_audio_card.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+ .probe = skylake_audio_probe,
+ .driver = {
+ .name = "skl_nau88l25_ssm4567_i2s",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
+MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s");
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index a73a431bd8b7..57333a476136 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -104,6 +104,53 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static unsigned int rates[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static unsigned int channels[] = {
+ 2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /*
+ * on this platform for PCM device we support,
+ * 48Khz
+ * stereo
+ * 16 bit audio
+ */
+
+ runtime->hw.channels_max = 2;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+ return 0;
+}
+
+static const struct snd_soc_ops skylake_rt286_fe_ops = {
+ .startup = skl_fe_startup,
+};
static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -112,12 +159,15 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
/* The output is 48KHz, stereo, 16bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
- params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
@@ -157,6 +207,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
SND_SOC_DPCM_TRIGGER_POST
},
.dpcm_playback = 1,
+ .ops = &skylake_rt286_fe_ops,
},
{
.name = "Skl Audio Capture Port",
@@ -172,6 +223,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
SND_SOC_DPCM_TRIGGER_POST
},
.dpcm_capture = 1,
+ .ops = &skylake_rt286_fe_ops,
},
{
.name = "Skl Audio Reference cap",
@@ -247,6 +299,7 @@ static struct platform_driver skylake_audio = {
.probe = skylake_audio_probe,
.driver = {
.name = "skl_alc286s_i2s",
+ .pm = &snd_soc_pm_ops,
},
};
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index d9105584c51f..658edce16761 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,5 +1,5 @@
snd-soc-sst-dsp-objs := sst-dsp.o
-snd-soc-sst-acpi-objs := sst-acpi.o
+snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o
ifneq ($(CONFIG_DW_DMAC_CORE),)
@@ -8,4 +8,3 @@ endif
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
-
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 67b6d3d52f57..7a85c576dad3 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -21,21 +21,12 @@
#include <linux/platform_device.h>
#include "sst-dsp.h"
+#include "sst-acpi.h"
#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
#define SST_LPT_DSP_DMA_SIZE (1024 - 1)
-/* Descriptor for SST ASoC machine driver */
-struct sst_acpi_mach {
- /* ACPI ID for the matching machine driver. Audio codec for instance */
- const u8 id[ACPI_ID_LEN];
- /* machine driver name */
- const char *drv_name;
- /* firmware file name */
- const char *fw_filename;
-};
-
/* Descriptor for setting up SST platform data */
struct sst_acpi_desc {
const char *drv_name;
@@ -88,28 +79,6 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
return;
}
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
-static struct sst_acpi_mach *sst_acpi_find_machine(
- struct sst_acpi_mach *machines)
-{
- struct sst_acpi_mach *mach;
- bool found = false;
-
- for (mach = machines; mach->id[0]; mach++)
- if (ACPI_SUCCESS(acpi_get_devices(mach->id,
- sst_acpi_mach_match,
- &found, NULL)) && found)
- return mach;
-
- return NULL;
-}
-
static int sst_acpi_probe(struct platform_device *pdev)
{
const struct acpi_device_id *id;
@@ -211,7 +180,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
}
static struct sst_acpi_mach haswell_machines[] = {
- { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+ { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL },
{}
};
@@ -229,7 +198,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
};
static struct sst_acpi_mach broadwell_machines[] = {
- { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+ { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
{}
};
@@ -247,8 +216,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
};
static struct sst_acpi_mach baytrail_machines[] = {
- { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
- { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+ { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
+ { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
{}
};
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
new file mode 100644
index 000000000000..3ee3b7ab5d03
--- /dev/null
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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/acpi.h>
+
+/* acpi match */
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+ /* ACPI ID for the matching machine driver. Audio codec for instance */
+ const u8 id[ACPI_ID_LEN];
+ /* machine driver name */
+ const char *drv_name;
+ /* firmware file name */
+ const char *fw_filename;
+
+ /* board name */
+ const char *board;
+ void (*machine_quirk)(void);
+ void *pdata;
+};
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 2151652d37b7..81aa1ed64201 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -243,7 +243,7 @@ struct sst_mem_block {
u32 size; /* block size */
u32 index; /* block index 0..N */
enum sst_mem_type type; /* block memory type IRAM/DRAM */
- struct sst_block_ops *ops; /* block operations, if any */
+ const struct sst_block_ops *ops;/* block operations, if any */
/* block status */
u32 bytes_used; /* bytes in use by modules */
@@ -308,6 +308,8 @@ struct sst_dsp {
/* SKL data */
+ const char *fw_name;
+
/* To allocate CL dma buffers */
struct skl_dsp_loader_ops dsp_ops;
struct skl_dsp_fw_ops fw_ops;
@@ -376,8 +378,8 @@ void sst_block_free_scratch(struct sst_dsp *dsp);
/* Register the DSPs memory blocks - would be nice to read from ACPI */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
- u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
- void *private);
+ u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+ u32 index, void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
/* Create/Free DMA resources */
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index 1636a1eeb002..bee04a9707d8 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -1014,8 +1014,8 @@ EXPORT_SYMBOL_GPL(sst_module_runtime_restore);
/* register a DSP memory block for use with FW based modules */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
- u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
- void *private)
+ u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+ u32 index, void *private)
{
struct sst_mem_block *block;
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
new file mode 100644
index 000000000000..dd077e116d25
--- /dev/null
+++ b/sound/soc/intel/common/sst-match-acpi.c
@@ -0,0 +1,43 @@
+/*
+ * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
+ *
+ * Copyright (c) 2013-15, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/acpi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-acpi.h"
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ *(bool *)context = true;
+ return AE_OK;
+}
+
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
+{
+ struct sst_acpi_mach *mach;
+ bool found = false;
+
+ for (mach = machines; mach->id[0]; mach++)
+ if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+ sst_acpi_mach_match,
+ &found, NULL)) && found)
+ return mach;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
index 7f94920c8a4d..b2bec36d074c 100644
--- a/sound/soc/intel/haswell/sst-haswell-dsp.c
+++ b/sound/soc/intel/haswell/sst-haswell-dsp.c
@@ -607,7 +607,7 @@ static int hsw_block_disable(struct sst_mem_block *block)
return 0;
}
-static struct sst_block_ops sst_hsw_ops = {
+static const struct sst_block_ops sst_hsw_ops = {
.enable = hsw_block_enable,
.disable = hsw_block_disable,
};
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 50a109503a3f..d71b58322cc7 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -96,7 +96,7 @@ int skl_init_dsp(struct skl *skl)
}
ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
- loader_ops, &skl->skl_sst);
+ skl->fw_name, loader_ops, &skl->skl_sst);
if (ret < 0)
return ret;
@@ -182,94 +182,6 @@ enum skl_bitdepth skl_get_bit_depth(int params)
}
}
-static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg)
-{
- u32 config;
-
- switch (ch_cfg) {
- case SKL_CH_CFG_MONO:
- config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT);
- break;
-
- case SKL_CH_CFG_STEREO:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4));
- break;
-
- case SKL_CH_CFG_2_1:
- config = (0xFFFFF000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4)
- | (SKL_CHANNEL_LFE << 8));
- break;
-
- case SKL_CH_CFG_3_0:
- config = (0xFFFFF000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8));
- break;
-
- case SKL_CH_CFG_3_1:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LFE << 12));
- break;
-
- case SKL_CH_CFG_QUATRO:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4)
- | (SKL_CHANNEL_LEFT_SURROUND << 8)
- | (SKL_CHANNEL_RIGHT_SURROUND << 12));
- break;
-
- case SKL_CH_CFG_4_0:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_CENTER_SURROUND << 12));
- break;
-
- case SKL_CH_CFG_5_0:
- config = (0xFFF00000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LEFT_SURROUND << 12)
- | (SKL_CHANNEL_RIGHT_SURROUND << 16));
- break;
-
- case SKL_CH_CFG_5_1:
- config = (0xFF000000 | SKL_CHANNEL_CENTER
- | (SKL_CHANNEL_LEFT << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LEFT_SURROUND << 12)
- | (SKL_CHANNEL_RIGHT_SURROUND << 16)
- | (SKL_CHANNEL_LFE << 20));
- break;
-
- case SKL_CH_CFG_DUAL_MONO:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_LEFT << 4));
- break;
-
- case SKL_CH_CFG_I2S_DUAL_STEREO_0:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4));
- break;
-
- case SKL_CH_CFG_I2S_DUAL_STEREO_1:
- config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8)
- | (SKL_CHANNEL_RIGHT << 12));
- break;
-
- default:
- config = 0xFFFFFFFF;
- break;
-
- }
-
- return config;
-}
-
/*
* Each module in DSP expects a base module configuration, which consists of
* PCM format information, which we calculate in driver and resource values
@@ -280,7 +192,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_base_cfg *base_cfg)
{
- struct skl_module_fmt *format = &mconfig->in_fmt;
+ struct skl_module_fmt *format = &mconfig->in_fmt[0];
base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
@@ -293,10 +205,9 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
format->bit_depth, format->valid_bit_depth,
format->ch_cfg);
- base_cfg->audio_fmt.channel_map = skl_create_channel_map(
- base_cfg->audio_fmt.ch_cfg);
+ base_cfg->audio_fmt.channel_map = format->ch_map;
- base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+ base_cfg->audio_fmt.interleaving = format->interleaving_style;
base_cfg->cps = mconfig->mcps;
base_cfg->ibs = mconfig->ibs;
@@ -399,7 +310,7 @@ static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
{
- struct skl_module_fmt *format = &mconfig->out_fmt;
+ struct skl_module_fmt *format = &mconfig->out_fmt[0];
out_fmt->number_of_channels = (u8)format->channels;
out_fmt->s_freq = format->s_freq;
@@ -407,8 +318,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
out_fmt->valid_bit_depth = format->valid_bit_depth;
out_fmt->ch_cfg = format->ch_cfg;
- out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg);
- out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+ out_fmt->channel_map = format->ch_map;
+ out_fmt->interleaving = format->interleaving_style;
+ out_fmt->sample_type = format->sample_type;
dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
out_fmt->number_of_channels, format->s_freq, format->bit_depth);
@@ -423,7 +335,7 @@ static void skl_set_src_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_src_module_cfg *src_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt;
+ struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)src_mconfig);
@@ -440,7 +352,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_up_down_mixer_cfg *mixer_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt;
+ struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
int i = 0;
skl_set_base_module_format(ctx, mconfig,
@@ -571,10 +483,10 @@ static int skl_get_queue_index(struct skl_module_pin *mpin,
* In static, the pin_index is fixed based on module_id and instance id
*/
static int skl_alloc_queue(struct skl_module_pin *mpin,
- struct skl_module_inst_id id, int max)
+ struct skl_module_cfg *tgt_cfg, int max)
{
int i;
-
+ struct skl_module_inst_id id = tgt_cfg->id;
/*
* if pin in dynamic, find first free pin
* otherwise find match module and instance id pin as topology will
@@ -583,16 +495,23 @@ static int skl_alloc_queue(struct skl_module_pin *mpin,
*/
for (i = 0; i < max; i++) {
if (mpin[i].is_dynamic) {
- if (!mpin[i].in_use) {
+ if (!mpin[i].in_use &&
+ mpin[i].pin_state == SKL_PIN_UNBIND) {
+
mpin[i].in_use = true;
mpin[i].id.module_id = id.module_id;
mpin[i].id.instance_id = id.instance_id;
+ mpin[i].tgt_mcfg = tgt_cfg;
return i;
}
} else {
if (mpin[i].id.module_id == id.module_id &&
- mpin[i].id.instance_id == id.instance_id)
+ mpin[i].id.instance_id == id.instance_id &&
+ mpin[i].pin_state == SKL_PIN_UNBIND) {
+
+ mpin[i].tgt_mcfg = tgt_cfg;
return i;
+ }
}
}
@@ -606,6 +525,28 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
mpin[q_index].id.module_id = 0;
mpin[q_index].id.instance_id = 0;
}
+ mpin[q_index].pin_state = SKL_PIN_UNBIND;
+ mpin[q_index].tgt_mcfg = NULL;
+}
+
+/* Module state will be set to unint, if all the out pin state is UNBIND */
+
+static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
+ struct skl_module_cfg *mcfg)
+{
+ int i;
+ bool found = false;
+
+ for (i = 0; i < max; i++) {
+ if (mpin[i].pin_state == SKL_PIN_UNBIND)
+ continue;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ mcfg->m_state = SKL_MODULE_UNINIT;
+ return;
}
/*
@@ -682,37 +623,30 @@ int skl_unbind_modules(struct skl_sst *ctx,
struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
- int src_index, dst_index;
+ int src_index, dst_index, src_pin_state, dst_pin_state;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
- if (src_mcfg->m_state != SKL_MODULE_BIND_DONE)
- return 0;
-
- /*
- * if intra module unbind, check if both modules are BIND,
- * then send unbind
- */
- if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) &&
- dst_mcfg->m_state != SKL_MODULE_BIND_DONE)
- return 0;
- else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
- dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
- return 0;
-
/* get src queue index */
src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
if (src_index < 0)
return -EINVAL;
- msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+ msg.src_queue = src_index;
/* get dst queue index */
dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
if (dst_index < 0)
return -EINVAL;
- msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+ msg.dst_queue = dst_index;
+
+ src_pin_state = src_mcfg->m_out_pin[src_index].pin_state;
+ dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state;
+
+ if (src_pin_state != SKL_PIN_BIND_DONE ||
+ dst_pin_state != SKL_PIN_BIND_DONE)
+ return 0;
msg.module_id = src_mcfg->id.module_id;
msg.instance_id = src_mcfg->id.instance_id;
@@ -722,10 +656,15 @@ int skl_unbind_modules(struct skl_sst *ctx,
ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
if (!ret) {
- src_mcfg->m_state = SKL_MODULE_UNINIT;
/* free queue only if unbind is success */
skl_free_queue(src_mcfg->m_out_pin, src_index);
skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+
+ /*
+ * check only if src module bind state, bind is
+ * always from src -> sink
+ */
+ skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg);
}
return ret;
@@ -744,8 +683,6 @@ int skl_bind_modules(struct skl_sst *ctx,
{
int ret;
struct skl_ipc_bind_unbind_msg msg;
- struct skl_module_inst_id src_id = src_mcfg->id;
- struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
int src_index, dst_index;
@@ -756,18 +693,18 @@ int skl_bind_modules(struct skl_sst *ctx,
dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
return 0;
- src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max);
+ src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max);
if (src_index < 0)
return -EINVAL;
- msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
- dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max);
+ msg.src_queue = src_index;
+ dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max);
if (dst_index < 0) {
skl_free_queue(src_mcfg->m_out_pin, src_index);
return -EINVAL;
}
- msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+ msg.dst_queue = dst_index;
dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
msg.src_queue, msg.dst_queue);
@@ -782,6 +719,8 @@ int skl_bind_modules(struct skl_sst *ctx,
if (!ret) {
src_mcfg->m_state = SKL_MODULE_BIND_DONE;
+ src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
+ dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
} else {
/* error case , if IPC fails, clear the queue index */
skl_free_queue(src_mcfg->m_out_pin, src_index);
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index b0c7bd113aac..6e4b21cdb1bd 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -55,7 +55,7 @@ void skl_nhlt_free(void *addr)
static struct nhlt_specific_cfg *skl_get_specific_cfg(
struct device *dev, struct nhlt_fmt *fmt,
- u8 no_ch, u32 rate, u16 bps)
+ u8 no_ch, u32 rate, u16 bps, u8 linktype)
{
struct nhlt_specific_cfg *sp_config;
struct wav_fmt *wfmt;
@@ -68,11 +68,17 @@ static struct nhlt_specific_cfg *skl_get_specific_cfg(
wfmt = &fmt_config->fmt_ext.fmt;
dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
wfmt->bits_per_sample, wfmt->samples_per_sec);
- if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
- wfmt->bits_per_sample == bps) {
+ if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) {
+ /*
+ * if link type is dmic ignore rate check as the blob is
+ * generic for all rates
+ */
sp_config = &fmt_config->config;
+ if (linktype == NHLT_LINK_DMIC)
+ return sp_config;
- return sp_config;
+ if (wfmt->samples_per_sec == rate)
+ return sp_config;
}
fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
@@ -115,7 +121,7 @@ struct nhlt_specific_cfg
struct device *dev = bus->dev;
struct nhlt_specific_cfg *sp_config;
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- u16 bps = num_ch * s_fmt;
+ u16 bps = (s_fmt == 16) ? 16 : 32;
u8 j;
dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
@@ -128,7 +134,8 @@ struct nhlt_specific_cfg
if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
fmt = (struct nhlt_fmt *)(epnt->config.caps +
epnt->config.size);
- sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
+ sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
+ s_rate, bps, link_type);
if (sp_config)
return sp_config;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index a2f94ce1679d..dae332beea3f 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -112,12 +112,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
struct hdac_ext_stream *stream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct skl_dma_params *dma_params;
- int ret;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- ret = pm_runtime_get_sync(dai->dev);
- if (ret < 0)
- return ret;
stream = snd_hdac_ext_stream_assign(ebus, substream,
skl_get_host_stream_type(ebus));
@@ -262,8 +258,6 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
*/
snd_soc_dai_set_dma_data(dai, substream, NULL);
- pm_runtime_mark_last_busy(dai->dev);
- pm_runtime_put_autosuspend(dai->dev);
kfree(dma_params);
}
@@ -291,7 +285,53 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream,
p_params.ch = params_channels(params);
p_params.s_freq = params_rate(params);
p_params.stream = substream->stream;
- skl_tplg_be_update_params(dai, &p_params);
+
+ return skl_tplg_be_update_params(dai, &p_params);
+}
+
+static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_ext_stream *stream;
+ int start;
+ unsigned long cookie;
+ struct hdac_stream *hstr;
+
+ stream = get_hdac_ext_stream(substream);
+ hstr = hdac_stream(stream);
+
+ if (!hstr->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ start = 1;
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ start = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+
+ if (start) {
+ snd_hdac_stream_start(hdac_stream(stream), true);
+ snd_hdac_stream_timecounter_init(hstr, 0);
+ } else {
+ snd_hdac_stream_stop(hdac_stream(stream));
+ }
+
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
return 0;
}
@@ -302,23 +342,48 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_cfg *mconfig;
+ int ret;
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
if (!mconfig)
return -EIO;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
+ /*
+ * Start HOST DMA and Start FE Pipe.This is to make sure that
+ * there are no underrun/overrun in the case when the FE
+ * pipeline is started but there is a delay in starting the
+ * DMA channel on the host.
+ */
+ ret = skl_decoupled_trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
return skl_run_pipe(ctx, mconfig->pipe);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- return skl_stop_pipe(ctx, mconfig->pipe);
+ case SNDRV_PCM_TRIGGER_STOP:
+ /*
+ * Stop FE Pipe first and stop DMA. This is to make sure that
+ * there are no underrun/overrun in the case if there is a delay
+ * between the two operations.
+ */
+ ret = skl_stop_pipe(ctx, mconfig->pipe);
+ if (ret < 0)
+ return ret;
+
+ ret = skl_decoupled_trigger(substream, cmd);
+ break;
default:
- return 0;
+ return -EINVAL;
}
+
+ return 0;
}
static int skl_link_hw_params(struct snd_pcm_substream *substream,
@@ -352,9 +417,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
p_params.stream = substream->stream;
p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
- skl_tplg_be_update_params(dai, &p_params);
-
- return 0;
+ return skl_tplg_be_update_params(dai, &p_params);
}
static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
@@ -443,19 +506,6 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static int skl_be_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- return pm_runtime_get_sync(dai->dev);
-}
-
-static void skl_be_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- pm_runtime_mark_last_busy(dai->dev);
- pm_runtime_put_autosuspend(dai->dev);
-}
-
static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.startup = skl_pcm_open,
.shutdown = skl_pcm_close,
@@ -466,24 +516,18 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
};
static struct snd_soc_dai_ops skl_dmic_dai_ops = {
- .startup = skl_be_startup,
.hw_params = skl_be_hw_params,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
- .startup = skl_be_startup,
.hw_params = skl_be_hw_params,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_ops skl_link_dai_ops = {
- .startup = skl_be_startup,
.prepare = skl_link_pcm_prepare,
.hw_params = skl_link_hw_params,
.hw_free = skl_link_hw_free,
.trigger = skl_link_pcm_trigger,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_driver skl_platform_dai[] = {
@@ -558,6 +602,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
+ .name = "SSP1 Pin",
+ .ops = &skl_be_ssp_dai_ops,
+ .playback = {
+ .stream_name = "ssp1 Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "ssp1 Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
.name = "iDisp Pin",
.ops = &skl_link_dai_ops,
.playback = {
@@ -688,66 +750,15 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct hdac_ext_stream *stream;
- int start;
- unsigned long cookie;
- struct hdac_stream *hstr;
-
- dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name);
-
- stream = get_hdac_ext_stream(substream);
- hstr = hdac_stream(stream);
-
- if (!hstr->prepared)
- return -EPIPE;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- start = 1;
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- start = 0;
- break;
-
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&bus->reg_lock, cookie);
-
- if (start)
- snd_hdac_stream_start(hdac_stream(stream), true);
- else
- snd_hdac_stream_stop(hdac_stream(stream));
-
- if (start)
- snd_hdac_stream_timecounter_init(hstr, 0);
-
- spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
- return 0;
-}
static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- if (ebus->ppcap)
- return skl_decoupled_trigger(substream, cmd);
- else
+ if (!ebus->ppcap)
return skl_coupled_trigger(substream, cmd);
+
+ return 0;
}
/* calculate runtime delay from LPIB */
@@ -789,7 +800,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
{
struct hdac_stream *hstr = hdac_stream(hstream);
struct snd_pcm_substream *substream = hstr->substream;
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_ext_bus *ebus;
unsigned int pos;
int delay;
@@ -800,6 +811,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
pos = 0;
if (substream->runtime) {
+ ebus = get_bus_ctx(substream);
delay = skl_get_delay_from_lpib(ebus, hstream, pos)
+ codec_delay;
substream->runtime->delay += delay;
@@ -941,7 +953,6 @@ int skl_platform_register(struct device *dev)
struct skl *skl = ebus_to_skl(ebus);
INIT_LIST_HEAD(&skl->ppl_list);
- INIT_LIST_HEAD(&skl->dapm_path_list);
ret = snd_soc_register_platform(dev, &skl_platform_drv);
if (ret) {
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index 44748ba98da2..b03d9db0acad 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -137,6 +137,11 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx)
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+
+ if (&ctx->cl_dev.dmab_data)
+ ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
+ if (&ctx->cl_dev.dmab_bdl)
+ ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
}
static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
@@ -175,6 +180,21 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
ctx->cl_dev.dma_buffer_offset, trigger);
dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
+ /*
+ * Check if the size exceeds buffer boundary. If it exceeds
+ * max_buffer size, then copy till buffer size and then copy
+ * remaining buffer from the start of ring buffer.
+ */
+ if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) {
+ unsigned int size_b = ctx->cl_dev.bufsize -
+ ctx->cl_dev.dma_buffer_offset;
+ memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
+ curr_pos, size_b);
+ size -= size_b;
+ curr_pos += size_b;
+ ctx->cl_dev.dma_buffer_offset = 0;
+ }
+
memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
curr_pos, size);
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 6bfcef449bdc..f2a69d9e56b3 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -139,7 +139,8 @@ void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_boot(struct sst_dsp *ctx);
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+ struct skl_sst **dsp);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#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 3345ea0d4414..95679c02c6ee 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -650,7 +650,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
header.primary, header.extension);
ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
- dx, sizeof(dx), NULL, 0);
+ dx, sizeof(*dx), NULL, 0);
if (ret < 0) {
dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 3b83dc99f1d4..e1d34d5c3f9a 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "../common/sst-ipc.h"
@@ -77,7 +78,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
init_waitqueue_head(&skl->boot_wait);
if (ctx->fw == NULL) {
- ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev);
+ ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) {
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
skl_dsp_disable_core(ctx);
@@ -115,27 +116,28 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
dev_err(ctx->dev,
"Timeout waiting for ROM init done, reg:0x%x\n", reg);
ret = -EIO;
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
}
ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
if (ret < 0) {
dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
} else {
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
ret = -EIO;
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
}
dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
}
return 0;
-
+transfer_firmware_failed:
+ ctx->cl_dev.ops.cl_cleanup_controller(ctx);
skl_load_base_firmware_failed:
skl_dsp_disable_core(ctx);
release_firmware(ctx->fw);
@@ -175,10 +177,15 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
dx.core_mask = SKL_DSP_CORE0_MASK;
dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to set DSP to D3 state\n");
- return ret;
- }
+ if (ret < 0)
+ dev_err(ctx->dev,
+ "D3 request to FW failed, continuing reset: %d", ret);
+
+ /* disable Interrupt */
+ ctx->cl_dev.ops.cl_cleanup_controller(ctx);
+ skl_cldma_int_disable(ctx);
+ skl_ipc_op_int_disable(ctx);
+ skl_ipc_int_disable(ctx);
ret = skl_dsp_disable_core(ctx);
if (ret < 0) {
@@ -187,12 +194,6 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
}
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
- /* disable Interrupt */
- ctx->cl_dev.ops.cl_cleanup_controller(ctx);
- skl_cldma_int_disable(ctx);
- skl_ipc_op_int_disable(ctx);
- skl_ipc_int_disable(ctx);
-
return ret;
}
@@ -223,7 +224,7 @@ static struct sst_dsp_device skl_dev = {
};
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
{
struct skl_sst *skl;
struct sst_dsp *sst;
@@ -244,6 +245,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
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),
@@ -259,15 +261,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
ret = sst->fw_ops.load_fw(sst);
if (ret < 0) {
dev_err(dev, "Load base fw failed : %d", ret);
- return ret;
+ goto cleanup;
}
if (dsp)
*dsp = skl;
- return 0;
+ return ret;
- skl_ipc_free(&skl->ipc);
+cleanup:
+ skl_sst_dsp_cleanup(dev, skl);
return ret;
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
@@ -275,7 +278,6 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{
skl_ipc_free(&ctx->ipc);
- ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index a7854c8fc523..0937ea2129c1 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -129,17 +129,15 @@ static void skl_dump_mconfig(struct skl_sst *ctx,
{
dev_dbg(ctx->dev, "Dumping config\n");
dev_dbg(ctx->dev, "Input Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
- dev_dbg(ctx->dev, "valid bit depth = %d\n",
- mcfg->in_fmt.valid_bit_depth);
+ dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
dev_dbg(ctx->dev, "Output Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
- dev_dbg(ctx->dev, "valid bit depth = %d\n",
- mcfg->out_fmt.valid_bit_depth);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
+ dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
}
static void skl_tplg_update_params(struct skl_module_fmt *fmt,
@@ -171,8 +169,9 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
int in_fixup, out_fixup;
struct skl_module_fmt *in_fmt, *out_fmt;
- in_fmt = &m_cfg->in_fmt;
- out_fmt = &m_cfg->out_fmt;
+ /* Fixups will be applied to pin 0 only */
+ in_fmt = &m_cfg->in_fmt[0];
+ out_fmt = &m_cfg->out_fmt[0];
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (is_fe) {
@@ -209,18 +208,25 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
struct skl_module_cfg *mcfg)
{
int multiplier = 1;
+ struct skl_module_fmt *in_fmt, *out_fmt;
+
+
+ /* Since fixups is applied to pin 0 only, ibs, obs needs
+ * change for pin 0 only
+ */
+ in_fmt = &mcfg->in_fmt[0];
+ out_fmt = &mcfg->out_fmt[0];
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
multiplier = 5;
-
- mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
- (mcfg->in_fmt.channels) *
- (mcfg->in_fmt.bit_depth >> 3) *
+ mcfg->ibs = (in_fmt->s_freq / 1000) *
+ (mcfg->in_fmt->channels) *
+ (mcfg->in_fmt->bit_depth >> 3) *
multiplier;
- mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
- (mcfg->out_fmt.channels) *
- (mcfg->out_fmt.bit_depth >> 3) *
+ mcfg->obs = (mcfg->out_fmt->s_freq / 1000) *
+ (mcfg->out_fmt->channels) *
+ (mcfg->out_fmt->bit_depth >> 3) *
multiplier;
}
@@ -397,41 +403,24 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
return 0;
}
-/*
- * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
- * we need to do following:
- * - Bind to sink pipeline
- * Since the sink pipes can be running and we don't get mixer event on
- * connect for already running mixer, we need to find the sink pipes
- * here and bind to them. This way dynamic connect works.
- * - Start sink pipeline, if not running
- * - Then run current pipe
- */
-static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
- struct skl *skl)
+static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
+ struct skl *skl,
+ struct skl_module_cfg *src_mconfig)
{
struct snd_soc_dapm_path *p;
- struct skl_dapm_path_list *path_list;
- struct snd_soc_dapm_widget *source, *sink;
- struct skl_module_cfg *src_mconfig, *sink_mconfig;
+ struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
+ struct skl_module_cfg *sink_mconfig;
struct skl_sst *ctx = skl->skl_sst;
- int ret = 0;
-
- source = w;
- src_mconfig = source->priv;
+ int ret;
- /*
- * find which sink it is connected to, bind with the sink,
- * if sink is not started, start sink pipe first, then start
- * this pipe
- */
- snd_soc_dapm_widget_for_each_source_path(w, p) {
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (!p->connect)
continue;
dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
+ next_sink = p->sink;
/*
* here we will check widgets in sink pipelines, so that
* can be any widgets type and we are only interested if
@@ -441,7 +430,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
is_skl_dsp_widget_type(p->sink)) {
sink = p->sink;
- src_mconfig = source->priv;
sink_mconfig = sink->priv;
/* Bind source to sink, mixin is always source */
@@ -451,32 +439,89 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
/* Start sinks pipe first */
if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
- ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+ if (sink_mconfig->pipe->conn_type !=
+ SKL_PIPE_CONN_TYPE_FE)
+ ret = skl_run_pipe(ctx,
+ sink_mconfig->pipe);
if (ret)
return ret;
}
-
- path_list = kzalloc(
- sizeof(struct skl_dapm_path_list),
- GFP_KERNEL);
- if (path_list == NULL)
- return -ENOMEM;
-
- /* Add connected path to one global list */
- path_list->dapm_path = p;
- list_add_tail(&path_list->node, &skl->dapm_path_list);
- break;
}
}
- /* Start source pipe last after starting all sinks */
- ret = skl_run_pipe(ctx, src_mconfig->pipe);
+ if (!sink)
+ return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+
+ return 0;
+}
+
+/*
+ * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
+ * we need to do following:
+ * - Bind to sink pipeline
+ * Since the sink pipes can be running and we don't get mixer event on
+ * connect for already running mixer, we need to find the sink pipes
+ * here and bind to them. This way dynamic connect works.
+ * - Start sink pipeline, if not running
+ * - Then run current pipe
+ */
+static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
+ struct skl *skl)
+{
+ struct skl_module_cfg *src_mconfig;
+ struct skl_sst *ctx = skl->skl_sst;
+ int ret = 0;
+
+ src_mconfig = w->priv;
+
+ /*
+ * find which sink it is connected to, bind with the sink,
+ * if sink is not started, start sink pipe first, then start
+ * this pipe
+ */
+ ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
if (ret)
return ret;
+ /* Start source pipe last after starting all sinks */
+ if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+ return skl_run_pipe(ctx, src_mconfig->pipe);
+
return 0;
}
+static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
+ struct snd_soc_dapm_widget *w, struct skl *skl)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *src_w = NULL;
+ struct skl_sst *ctx = skl->skl_sst;
+
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ src_w = p->source;
+ if (!p->connect)
+ continue;
+
+ dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
+ dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+
+ /*
+ * here we will check widgets in sink pipelines, so that can
+ * be any widgets type and we are only interested if they are
+ * ones used for SKL so check that first
+ */
+ if ((p->source->priv != NULL) &&
+ is_skl_dsp_widget_type(p->source)) {
+ return p->source;
+ }
+ }
+
+ if (src_w != NULL)
+ return skl_get_src_dsp_widget(src_w, skl);
+
+ return NULL;
+}
+
/*
* in the Post-PMU event of mixer we need to do following:
* - Check if this pipe is running
@@ -490,7 +535,6 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
int ret = 0;
- struct snd_soc_dapm_path *p;
struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
struct skl_sst *ctx = skl->skl_sst;
@@ -504,32 +548,18 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
* one more sink before this sink got connected, Since source is
* started, bind this sink to source and start this pipe.
*/
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (!p->connect)
- continue;
-
- dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
- dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+ source = skl_get_src_dsp_widget(w, skl);
+ if (source != NULL) {
+ src_mconfig = source->priv;
+ sink_mconfig = sink->priv;
+ src_pipe_started = 1;
/*
- * here we will check widgets in sink pipelines, so that
- * can be any widgets type and we are only interested if
- * they are ones used for SKL so check that first
+ * check pipe state, then no need to bind or start the
+ * pipe
*/
- if ((p->source->priv != NULL) &&
- is_skl_dsp_widget_type(p->source)) {
- source = p->source;
- src_mconfig = source->priv;
- sink_mconfig = sink->priv;
- src_pipe_started = 1;
-
- /*
- * check pipe state, then no need to bind or start
- * the pipe
- */
- if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
- src_pipe_started = 0;
- }
+ if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
+ src_pipe_started = 0;
}
if (src_pipe_started) {
@@ -537,7 +567,8 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+ if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+ ret = skl_run_pipe(ctx, sink_mconfig->pipe);
}
return ret;
@@ -552,52 +583,35 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
- struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, path_found = 0;
- struct skl_dapm_path_list *path_list, *tmp_list;
+ int ret = 0, i;
struct skl_sst *ctx = skl->skl_sst;
- sink = w;
- sink_mconfig = sink->priv;
+ sink_mconfig = w->priv;
/* Stop the pipe */
ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
if (ret)
return ret;
- /*
- * This list, dapm_path_list handling here does not need any locks
- * as we are under dapm lock while handling widget events.
- * List can be manipulated safely only under dapm widgets handler
- * routines
- */
- list_for_each_entry_safe(path_list, tmp_list,
- &skl->dapm_path_list, node) {
- if (path_list->dapm_path->sink == sink) {
- dev_dbg(ctx->dev, "Path found = %s\n",
- path_list->dapm_path->name);
- source = path_list->dapm_path->source;
- src_mconfig = source->priv;
- path_found = 1;
-
- list_del(&path_list->node);
- kfree(path_list);
- break;
- }
- }
-
- /*
- * 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.
- */
- if (path_found) {
- ret = skl_stop_pipe(ctx, src_mconfig->pipe);
- if (ret < 0)
- return ret;
+ for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+ if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+ 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);
+ ret = skl_unbind_modules(ctx,
+ src_mconfig, sink_mconfig);
+ }
}
return ret;
@@ -626,6 +640,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
list_for_each_entry(w_module, &s_pipe->w_list, node) {
dst_module = w_module->w->priv;
+ skl_tplg_free_pipe_mcps(skl, dst_module);
if (src_module == NULL) {
src_module = dst_module;
continue;
@@ -653,47 +668,34 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
- struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, path_found = 0;
- struct skl_dapm_path_list *path_list, *tmp_path_list;
+ int ret = 0, i;
struct skl_sst *ctx = skl->skl_sst;
- source = w;
- src_mconfig = source->priv;
+ src_mconfig = w->priv;
- skl_tplg_free_pipe_mcps(skl, src_mconfig);
/* Stop the pipe since this is a mixin module */
ret = skl_stop_pipe(ctx, src_mconfig->pipe);
if (ret)
return ret;
- list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) {
- if (path_list->dapm_path->source == source) {
- dev_dbg(ctx->dev, "Path found = %s\n",
- path_list->dapm_path->name);
- sink = path_list->dapm_path->sink;
- sink_mconfig = sink->priv;
- path_found = 1;
-
- list_del(&path_list->node);
- kfree(path_list);
- break;
+ for (i = 0; i < src_mconfig->max_out_queue; i++) {
+ if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+ sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
+ if (!sink_mconfig)
+ continue;
+ /*
+ * This is a connecter and if path is found that means
+ * unbind between source and sink has not happened yet
+ */
+ ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
+ if (ret < 0)
+ return ret;
+ ret = skl_unbind_modules(ctx, src_mconfig,
+ sink_mconfig);
}
}
- /*
- * This is a connector and if path is found that means
- * unbind between source and sink has not happened yet
- */
- if (path_found) {
- ret = skl_stop_pipe(ctx, src_mconfig->pipe);
- if (ret < 0)
- return ret;
-
- ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
- }
-
return ret;
}
@@ -790,9 +792,9 @@ int skl_tplg_update_pipe_params(struct device *dev,
memcpy(pipe->p_params, params, sizeof(*params));
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
- format = &mconfig->in_fmt;
+ format = &mconfig->in_fmt[0];
else
- format = &mconfig->out_fmt;
+ format = &mconfig->out_fmt[0];
/* set the hw_params */
format->s_freq = params->s_freq;
@@ -809,6 +811,7 @@ int skl_tplg_update_pipe_params(struct device *dev,
break;
case SKL_DEPTH_24BIT:
+ case SKL_DEPTH_32BIT:
format->bit_depth = SKL_DEPTH_32BIT;
break;
@@ -846,7 +849,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
w = dai->playback_widget;
snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (p->connect && p->sink->power &&
- is_skl_dsp_widget_type(p->sink))
+ !is_skl_dsp_widget_type(p->sink))
continue;
if (p->sink->priv) {
@@ -859,7 +862,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
w = dai->capture_widget;
snd_soc_dapm_widget_for_each_source_path(w, p) {
if (p->connect && p->source->power &&
- is_skl_dsp_widget_type(p->source))
+ !is_skl_dsp_widget_type(p->source))
continue;
if (p->source->priv) {
@@ -920,6 +923,9 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
memcpy(pipe->p_params, params, sizeof(*params));
+ if (link_type == NHLT_LINK_HDA)
+ return 0;
+
/* update the blob based on virtual bus_id*/
cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
params->s_fmt, params->ch,
@@ -950,18 +956,13 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
if (p->connect && is_skl_dsp_widget_type(p->source) &&
p->source->priv) {
- if (!p->source->power) {
- ret = skl_tplg_be_fill_pipe_params(
- dai, p->source->priv,
- params);
- if (ret < 0)
- return ret;
- } else {
- return -EBUSY;
- }
+ ret = skl_tplg_be_fill_pipe_params(dai,
+ p->source->priv, params);
+ if (ret < 0)
+ return ret;
} else {
- ret = skl_tplg_be_set_src_pipe_params(
- dai, p->source, params);
+ ret = skl_tplg_be_set_src_pipe_params(dai,
+ p->source, params);
if (ret < 0)
return ret;
}
@@ -980,15 +981,10 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
if (p->connect && is_skl_dsp_widget_type(p->sink) &&
p->sink->priv) {
- if (!p->sink->power) {
- ret = skl_tplg_be_fill_pipe_params(
- dai, p->sink->priv, params);
- if (ret < 0)
- return ret;
- } else {
- return -EBUSY;
- }
-
+ ret = skl_tplg_be_fill_pipe_params(dai,
+ p->sink->priv, params);
+ if (ret < 0)
+ return ret;
} else {
ret = skl_tplg_be_set_sink_pipe_params(
dai, p->sink, params);
@@ -1045,6 +1041,7 @@ static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
m_pin[i].id.instance_id = dfw_pin[i].instance_id;
m_pin[i].in_use = false;
m_pin[i].is_dynamic = is_dynamic;
+ m_pin[i].pin_state = SKL_PIN_UNBIND;
}
}
@@ -1092,6 +1089,24 @@ static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
return ppl->pipe;
}
+static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
+ struct skl_dfw_module_fmt *src_fmt,
+ int pins)
+{
+ int i;
+
+ for (i = 0; i < pins; i++) {
+ dst_fmt[i].channels = src_fmt[i].channels;
+ dst_fmt[i].s_freq = src_fmt[i].freq;
+ dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
+ dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
+ dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
+ dst_fmt[i].ch_map = src_fmt[i].ch_map;
+ dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
+ dst_fmt[i].sample_type = src_fmt[i].sample_type;
+ }
+}
+
/*
* Topology core widget load callback
*
@@ -1130,18 +1145,11 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
mconfig->max_in_queue = dfw_config->max_in_queue;
mconfig->max_out_queue = dfw_config->max_out_queue;
mconfig->is_loadable = dfw_config->is_loadable;
- mconfig->in_fmt.channels = dfw_config->in_fmt.channels;
- mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq;
- mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth;
- mconfig->in_fmt.valid_bit_depth =
- dfw_config->in_fmt.valid_bit_depth;
- mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg;
- mconfig->out_fmt.channels = dfw_config->out_fmt.channels;
- mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq;
- mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth;
- mconfig->out_fmt.valid_bit_depth =
- dfw_config->out_fmt.valid_bit_depth;
- mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg;
+ skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
+ MODULE_MAX_IN_PINS);
+ skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
+ MODULE_MAX_OUT_PINS);
+
mconfig->params_fixup = dfw_config->params_fixup;
mconfig->converter = dfw_config->converter;
mconfig->m_type = dfw_config->module_type;
@@ -1156,10 +1164,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
mconfig->time_slot = dfw_config->time_slot;
mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
- mconfig->m_in_pin = devm_kzalloc(bus->dev,
- (mconfig->max_in_queue) *
- sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
+ if (dfw_config->is_loadable)
+ memcpy(mconfig->guid, dfw_config->uuid,
+ ARRAY_SIZE(dfw_config->uuid));
+
+ mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
+ sizeof(*mconfig->m_in_pin),
+ GFP_KERNEL);
if (!mconfig->m_in_pin)
return -ENOMEM;
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 76053a8de41c..57cb7b8dd269 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -36,6 +36,9 @@
/* Maximum number of coefficients up down mixer module */
#define UP_DOWN_MIXER_MAX_COEFF 6
+#define MODULE_MAX_IN_PINS 8
+#define MODULE_MAX_OUT_PINS 8
+
enum skl_channel_index {
SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1,
@@ -55,12 +58,6 @@ enum skl_bitdepth {
SKL_DEPTH_INVALID
};
-enum skl_interleaving {
- /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
- SKL_INTERLEAVING_PER_CHANNEL = 0,
- /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
- SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
enum skl_s_freq {
SKL_FS_8000 = 8000,
@@ -178,18 +175,29 @@ struct skl_module_fmt {
u32 bit_depth;
u32 valid_bit_depth;
u32 ch_cfg;
+ u32 interleaving_style;
+ u32 sample_type;
+ u32 ch_map;
};
+struct skl_module_cfg;
+
struct skl_module_inst_id {
u32 module_id;
u32 instance_id;
};
+enum skl_module_pin_state {
+ SKL_PIN_UNBIND = 0,
+ SKL_PIN_BIND_DONE = 1,
+};
+
struct skl_module_pin {
struct skl_module_inst_id id;
- u8 pin_index;
bool is_dynamic;
bool in_use;
+ enum skl_module_pin_state pin_state;
+ struct skl_module_cfg *tgt_mcfg;
};
struct skl_specific_cfg {
@@ -238,9 +246,13 @@ enum skl_module_state {
};
struct skl_module_cfg {
+ char guid[SKL_UUID_STR_SZ];
struct skl_module_inst_id id;
- struct skl_module_fmt in_fmt;
- struct skl_module_fmt out_fmt;
+ u8 domain;
+ bool homogenous_inputs;
+ bool homogenous_outputs;
+ struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS];
+ struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS];
u8 max_in_queue;
u8 max_out_queue;
u8 in_queue_mask;
@@ -272,11 +284,6 @@ struct skl_pipeline {
struct list_head node;
};
-struct skl_dapm_path_list {
- struct snd_soc_dapm_path *dapm_path;
- struct list_head node;
-};
-
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 2bc396d54cbe..20c068754d08 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -32,6 +32,7 @@
#define MAX_IN_QUEUE 8
#define MAX_OUT_QUEUE 8
+#define SKL_UUID_STR_SZ 40
/* Event types goes here */
/* Reserve event type 0 for no event handlers */
enum skl_event_types {
@@ -72,6 +73,7 @@ enum skl_ch_cfg {
SKL_CH_CFG_DUAL_MONO = 9,
SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+ SKL_CH_CFG_4_CHANNEL = 12,
SKL_CH_CFG_INVALID
};
@@ -110,6 +112,36 @@ enum skl_dev_type {
SKL_DEVICE_NONE
};
+/**
+ * enum skl_interleaving - interleaving style
+ *
+ * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
+ * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
+ */
+enum skl_interleaving {
+ SKL_INTERLEAVING_PER_CHANNEL = 0,
+ SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_sample_type {
+ SKL_SAMPLE_TYPE_INT_MSB = 0,
+ SKL_SAMPLE_TYPE_INT_LSB = 1,
+ SKL_SAMPLE_TYPE_INT_SIGNED = 2,
+ SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
+ SKL_SAMPLE_TYPE_FLOAT = 4
+};
+
+enum module_pin_type {
+ /* All pins of the module takes same PCM inputs or outputs
+ * e.g. mixout
+ */
+ SKL_PIN_TYPE_HOMOGENEOUS,
+ /* All pins of the module takes different PCM inputs or outputs
+ * e.g mux
+ */
+ SKL_PIN_TYPE_HETEROGENEOUS,
+};
+
struct skl_dfw_module_pin {
u16 module_id;
u16 instance_id;
@@ -121,9 +153,15 @@ struct skl_dfw_module_fmt {
u32 bit_depth;
u32 valid_bit_depth;
u32 ch_cfg;
+ u32 interleaving_style;
+ u32 sample_type;
+ u32 ch_map;
} __packed;
struct skl_dfw_module_caps {
+ u32 set_params:1;
+ u32 rsvd:31;
+ u32 param_id;
u32 caps_size;
u32 caps[HDA_SST_CFG_MAX];
};
@@ -131,41 +169,57 @@ struct skl_dfw_module_caps {
struct skl_dfw_pipe {
u8 pipe_id;
u8 pipe_priority;
- u16 conn_type;
- u32 memory_pages;
+ u16 conn_type:4;
+ u16 rsvd:4;
+ u16 memory_pages:8;
} __packed;
struct skl_dfw_module {
+ char uuid[SKL_UUID_STR_SZ];
+
u16 module_id;
u16 instance_id;
u32 max_mcps;
- u8 core_id;
- u8 max_in_queue;
- u8 max_out_queue;
- u8 is_loadable;
- u8 conn_type;
- u8 dev_type;
- u8 hw_conn_type;
- u8 time_slot;
+ u32 mem_pages;
u32 obs;
u32 ibs;
- u32 params_fixup;
- u32 converter;
- u32 module_type;
u32 vbus_id;
- u8 is_dynamic_in_pin;
- u8 is_dynamic_out_pin;
+
+ u32 max_in_queue:8;
+ u32 max_out_queue:8;
+ u32 time_slot:8;
+ u32 core_id:4;
+ u32 rsvd1:4;
+
+ u32 module_type:8;
+ u32 conn_type:4;
+ u32 dev_type:4;
+ u32 hw_conn_type:4;
+ u32 rsvd2:12;
+
+ u32 params_fixup:8;
+ u32 converter:8;
+ u32 input_pin_type:1;
+ u32 output_pin_type:1;
+ u32 is_dynamic_in_pin:1;
+ u32 is_dynamic_out_pin:1;
+ u32 is_loadable:1;
+ u32 rsvd3:11;
+
struct skl_dfw_pipe pipe;
- struct skl_dfw_module_fmt in_fmt;
- struct skl_dfw_module_fmt out_fmt;
+ struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
+ struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
struct skl_dfw_module_caps caps;
} __packed;
struct skl_dfw_algo_data {
+ u32 set_params:1;
+ u32 rsvd:31;
+ u32 param_id;
u32 max;
- char *params;
+ char params[0];
} __packed;
#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 5319529aedf7..d3e87b6f93fe 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -26,6 +26,7 @@
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
+#include "../common/sst-acpi.h"
#include "skl.h"
/*
@@ -129,6 +130,37 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
return 0;
}
+#ifdef CONFIG_PM
+static int _skl_suspend(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ int ret;
+
+ snd_hdac_ext_bus_link_power_down_all(ebus);
+
+ ret = skl_suspend_dsp(skl);
+ if (ret < 0)
+ return ret;
+
+ snd_hdac_bus_stop_chip(bus);
+ snd_hdac_bus_enter_link_reset(bus);
+
+ return 0;
+}
+
+static int _skl_resume(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ skl_init_pci(skl);
+ snd_hdac_bus_init_chip(bus, true);
+
+ return skl_resume_dsp(skl);
+}
+#endif
+
#ifdef CONFIG_PM_SLEEP
/*
* power management
@@ -137,26 +169,16 @@ static int skl_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- snd_hdac_bus_stop_chip(bus);
- snd_hdac_bus_enter_link_reset(bus);
-
- return 0;
+ return _skl_suspend(ebus);
}
static int skl_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *hda = ebus_to_skl(ebus);
-
- skl_init_pci(hda);
-
- snd_hdac_bus_init_chip(bus, 1);
- return 0;
+ return _skl_resume(ebus);
}
#endif /* CONFIG_PM_SLEEP */
@@ -166,24 +188,10 @@ static int skl_runtime_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
- int ret;
dev_dbg(bus->dev, "in %s\n", __func__);
- /* enable controller wake up event */
- snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
-
- snd_hdac_ext_bus_link_power_down_all(ebus);
-
- ret = skl_suspend_dsp(skl);
- if (ret < 0)
- return ret;
-
- snd_hdac_bus_stop_chip(bus);
- snd_hdac_bus_enter_link_reset(bus);
-
- return 0;
+ return _skl_suspend(ebus);
}
static int skl_runtime_resume(struct device *dev)
@@ -191,20 +199,10 @@ static int skl_runtime_resume(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
- int status;
dev_dbg(bus->dev, "in %s\n", __func__);
- /* Read STATESTS before controller reset */
- status = snd_hdac_chip_readw(bus, STATESTS);
-
- skl_init_pci(skl);
- snd_hdac_bus_init_chip(bus, true);
- /* disable controller Wake Up event */
- snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
-
- return skl_resume_dsp(skl);
+ return _skl_resume(ebus);
}
#endif /* CONFIG_PM */
@@ -241,6 +239,43 @@ static int skl_free(struct hdac_ext_bus *ebus)
return 0;
}
+static int skl_machine_device_register(struct skl *skl, void *driver_data)
+{
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct platform_device *pdev;
+ struct sst_acpi_mach *mach = driver_data;
+ int ret;
+
+ mach = sst_acpi_find_machine(mach);
+ if (mach == NULL) {
+ dev_err(bus->dev, "No matching machine driver found\n");
+ return -ENODEV;
+ }
+ skl->fw_name = mach->fw_filename;
+
+ pdev = platform_device_alloc(mach->drv_name, -1);
+ if (pdev == NULL) {
+ dev_err(bus->dev, "platform device alloc failed\n");
+ return -EIO;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(bus->dev, "failed to add machine device\n");
+ platform_device_put(pdev);
+ return -EIO;
+ }
+ skl->i2s_dev = pdev;
+
+ return 0;
+}
+
+static void skl_machine_device_unregister(struct skl *skl)
+{
+ if (skl->i2s_dev)
+ platform_device_unregister(skl->i2s_dev);
+}
+
static int skl_dmic_device_register(struct skl *skl)
{
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
@@ -434,8 +469,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
/* codec detection */
if (!bus->codec_mask) {
- dev_err(bus->dev, "no codecs found!\n");
- return -ENODEV;
+ dev_info(bus->dev, "no hda codecs found!\n");
}
return 0;
@@ -470,10 +504,15 @@ static int skl_probe(struct pci_dev *pci,
/* check if dsp is there */
if (ebus->ppcap) {
+ err = skl_machine_device_register(skl,
+ (void *)pci_id->driver_data);
+ if (err < 0)
+ goto out_free;
+
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_free;
+ goto out_mach_free;
}
}
if (ebus->mlcap)
@@ -508,6 +547,8 @@ out_dmic_free:
skl_dmic_device_unregister(skl);
out_dsp_free:
skl_free_dsp(skl);
+out_mach_free:
+ skl_machine_device_unregister(skl);
out_free:
skl->init_failed = 1;
skl_free(ebus);
@@ -525,15 +566,24 @@ static void skl_remove(struct pci_dev *pci)
pci_dev_put(pci);
skl_platform_unregister(&pci->dev);
skl_free_dsp(skl);
+ skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl);
skl_free(ebus);
dev_set_drvdata(&pci->dev, NULL);
}
+static struct sst_acpi_mach sst_skl_devdata[] = {
+ { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
+ { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin",
+ NULL, NULL, NULL },
+ {}
+};
+
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */
- { PCI_DEVICE(0x8086, 0x9d70), 0},
+ { PCI_DEVICE(0x8086, 0x9d70),
+ .driver_data = (unsigned long)&sst_skl_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 dd2e79ae45a8..774c29cf84dc 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -61,13 +61,15 @@ struct skl {
unsigned int init_failed:1; /* delayed init failed */
struct platform_device *dmic_dev;
+ struct platform_device *i2s_dev;
void *nhlt; /* nhlt ptr */
struct skl_sst *skl_sst; /* sst skl ctx */
struct skl_dsp_resource resource;
struct list_head ppl_list;
- struct list_head dapm_path_list;
+
+ const char *fw_name;
};
#define skl_to_ebus(s) (&(s)->ebus)