Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
0c2964cb38
@ -497,7 +497,15 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
|
||||
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
||||
unsigned int dai_fmt);
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour);
|
||||
#else
|
||||
static inline int snd_soc_set_dmi_name(struct snd_soc_card *card,
|
||||
const char *flavour)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
|
@ -268,7 +268,7 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
|
||||
unsigned int offset;
|
||||
unsigned int counter = 0;
|
||||
|
||||
offset = snd_hdac_chip_readl(bus, LLCH);
|
||||
offset = snd_hdac_chip_readw(bus, LLCH);
|
||||
|
||||
/* Lets walk the linked capabilities list */
|
||||
do {
|
||||
|
@ -469,7 +469,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
format = snd_hdac_calc_stream_format(params_rate(hparams),
|
||||
params_channels(hparams), params_format(hparams),
|
||||
24, 0);
|
||||
dai->driver->playback.sig_bits, 0);
|
||||
|
||||
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
|
||||
if (!pcm)
|
||||
@ -1419,8 +1419,8 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
|
||||
hdmi_dais[i].playback.rate_min = rate_min;
|
||||
hdmi_dais[i].playback.channels_min = 2;
|
||||
hdmi_dais[i].playback.channels_max = 2;
|
||||
hdmi_dais[i].playback.sig_bits = bps;
|
||||
hdmi_dais[i].ops = &hdmi_dai_ops;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -2835,6 +2835,27 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -202,6 +202,30 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
|
||||
platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_DA7213
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
|
||||
platforms with DA7212/7213 audio codec.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for the MinnowBoard Max or
|
||||
Up boards and provides access to I2S signals on the Low-Speed
|
||||
connector
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_SKYLAKE
|
||||
tristate
|
||||
select SND_HDA_EXT_CORE
|
||||
|
@ -420,7 +420,21 @@ static const struct dmi_system_id byt_table[] = {
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
@ -480,12 +494,23 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
||||
&byt_rvp_platform_data },
|
||||
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
{"DLGS7212", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
{"DLGS7213", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
/* some Baytrail platforms rely on RT5645, use CHT machine driver */
|
||||
{"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
{"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
|
||||
/*
|
||||
* This is always last in the table so that it is selected only when
|
||||
* enabled explicitly and there is no codec-related information in SSDT
|
||||
*/
|
||||
{"80860F28", "bytcht_nocodec", "intel/fw_sst_0f28.bin", "bytcht_nocodec", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
||||
@ -504,6 +529,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
||||
|
||||
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
{"DLGS7212", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
|
||||
&chv_platform_data },
|
||||
{"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
|
||||
&chv_platform_data },
|
||||
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
|
||||
&chv_platform_data },
|
||||
@ -512,6 +541,14 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
||||
/* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
|
||||
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL,
|
||||
&chv_platform_data },
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
|
||||
/*
|
||||
* This is always last in the table so that it is selected only when
|
||||
* enabled explicitly and there is no codec-related information in SSDT
|
||||
*/
|
||||
{"808622A8", "bytcht_nocodec", "intel/fw_sst_22a8.bin", "bytcht_nocodec", NULL,
|
||||
&chv_platform_data },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -236,7 +236,9 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
|
||||
retval = init->result;
|
||||
goto ret;
|
||||
}
|
||||
dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n",
|
||||
if (memcmp(&sst_drv_ctx->fw_version, &init->fw_version,
|
||||
sizeof(init->fw_version)))
|
||||
dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n",
|
||||
init->fw_version.type, init->fw_version.major,
|
||||
init->fw_version.minor, init->fw_version.build);
|
||||
dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n",
|
||||
|
@ -10,6 +10,8 @@ snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
|
||||
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-sst-byt-cht-da7213-objs := bytcht_da7213.o
|
||||
snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
|
||||
snd-soc-skl_rt286-objs := skl_rt286.o
|
||||
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
|
||||
snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
|
||||
@ -26,6 +28,8 @@ obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
|
||||
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_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
|
||||
|
@ -193,13 +193,12 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
|
||||
RT5677_CLK_SEL_I2S1_ASRC);
|
||||
|
||||
/* Request rt5677 GPIO for headphone amp control */
|
||||
bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev,
|
||||
"headphone-enable", 0, 0);
|
||||
bdw_rt5677->gpio_hp_en = devm_gpiod_get(codec->dev, "headphone-enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(bdw_rt5677->gpio_hp_en)) {
|
||||
dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n");
|
||||
return PTR_ERR(bdw_rt5677->gpio_hp_en);
|
||||
}
|
||||
gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0);
|
||||
|
||||
/* Create and initialize headphone jack */
|
||||
if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack",
|
||||
|
@ -269,9 +269,6 @@ static struct snd_soc_card broadwell_rt286 = {
|
||||
static int broadwell_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
broadwell_rt286.dev = &pdev->dev;
|
||||
|
||||
snd_soc_set_dmi_name(&broadwell_rt286, NULL);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,54 @@ enum {
|
||||
BXT_DPCM_AUDIO_HDMI3_PB,
|
||||
};
|
||||
|
||||
static inline struct snd_soc_dai *bxt_get_codec_dai(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
list_for_each_entry(rtd, &card->rtd_list, list) {
|
||||
|
||||
if (!strncmp(rtd->codec_dai->name, BXT_DIALOG_CODEC_DAI,
|
||||
strlen(BXT_DIALOG_CODEC_DAI)))
|
||||
return rtd->codec_dai;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
int ret = 0;
|
||||
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
|
||||
codec_dai = bxt_get_codec_dai(card);
|
||||
if (!codec_dai) {
|
||||
dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_OFF(event)) {
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0,
|
||||
DA7219_SYSCLK_MCLK, 0, 0);
|
||||
if (ret)
|
||||
dev_err(card->dev, "failed to stop PLL: %d\n", ret);
|
||||
} else if(SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai,
|
||||
DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN);
|
||||
if (ret)
|
||||
dev_err(card->dev, "can't set codec sysclk configuration\n");
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0,
|
||||
DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
|
||||
if (ret)
|
||||
dev_err(card->dev, "failed to start PLL: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new broxton_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
@ -69,6 +117,8 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("HDMI1", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI2", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI3", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route broxton_map[] = {
|
||||
@ -109,6 +159,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
|
||||
/* DMIC */
|
||||
{"dmic01_hifi", NULL, "DMIC01 Rx"},
|
||||
{"DMIC01 Rx", NULL, "DMIC AIF"},
|
||||
|
||||
{ "Headphone Jack", NULL, "Platform Clock" },
|
||||
{ "Headset Mic", NULL, "Platform Clock" },
|
||||
};
|
||||
|
||||
static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
@ -243,49 +296,6 @@ static const struct snd_soc_ops broxton_da7219_fe_ops = {
|
||||
.startup = bxt_fe_startup,
|
||||
};
|
||||
|
||||
static int broxton_da7219_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,
|
||||
DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0)
|
||||
dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0,
|
||||
DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
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_pll(codec_dai, 0,
|
||||
DA7219_SYSCLK_MCLK, 0, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops broxton_da7219_ops = {
|
||||
.hw_params = broxton_da7219_hw_params,
|
||||
.hw_free = broxton_da7219_hw_free,
|
||||
};
|
||||
|
||||
static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@ -467,7 +477,6 @@ static struct snd_soc_dai_link broxton_dais[] = {
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ignore_pmdown_time = 1,
|
||||
.be_hw_params_fixup = broxton_ssp_fixup,
|
||||
.ops = &broxton_da7219_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
|
@ -274,12 +274,15 @@ static int bxt_fe_startup(struct snd_pcm_substream *substream)
|
||||
* 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);
|
||||
|
||||
|
283
sound/soc/intel/boards/bytcht_da7213.c
Normal file
283
sound/soc/intel/boards/bytcht_da7213.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* bytcht-da7213.c - ASoc Machine driver for Intel Baytrail and
|
||||
* Cherrytrail-based platforms, with Dialog DA7213 codec
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
* Author: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/platform_sst_audio.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include "../../codecs/da7213.h"
|
||||
#include "../atom/sst-atom-controls.h"
|
||||
#include "../common/sst-acpi.h"
|
||||
|
||||
static const struct snd_kcontrol_new controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Aux In"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic", NULL),
|
||||
SND_SOC_DAPM_LINE("Aux In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map[] = {
|
||||
{"Headphone Jack", NULL, "HPL"},
|
||||
{"Headphone Jack", NULL, "HPR"},
|
||||
|
||||
{"AUXL", NULL, "Aux In"},
|
||||
{"AUXR", NULL, "Aux In"},
|
||||
|
||||
/* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
|
||||
{"MIC1", NULL, "Headset Mic"},
|
||||
{"MIC2", NULL, "Mic"},
|
||||
|
||||
/* SOC-codec link */
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx"},
|
||||
{"codec_in1", NULL, "ssp2 Rx"},
|
||||
|
||||
{"Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Rx", NULL, "Capture"},
|
||||
};
|
||||
|
||||
static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
|
||||
/* The DSP will convert the FE rate to 48k, stereo, 24bits */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot, override config
|
||||
* with explicit setting to I2S 2ch 24-bit. The word length is set with
|
||||
* dai_set_tdm_slot() since there is no other API exposed
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aif1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_hw_constraint_single(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_RATE, 48000);
|
||||
}
|
||||
|
||||
static int aif1_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, DA7213_CLKSRC_MCLK,
|
||||
19200000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0)
|
||||
dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0,
|
||||
DA7213_SYSCLK_PLL_SRM, 0, DA7213_PLL_FREQ_OUT_98304000);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aif1_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
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_pll(codec_dai, 0,
|
||||
DA7213_SYSCLK_MCLK, 0, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops aif1_ops = {
|
||||
.startup = aif1_startup,
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops ssp2_ops = {
|
||||
.hw_params = aif1_hw_params,
|
||||
.hw_free = aif1_hw_free,
|
||||
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link dailink[] = {
|
||||
[MERR_DPCM_AUDIO] = {
|
||||
.name = "Audio Port",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "media-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.nonatomic = true,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_DEEP_BUFFER] = {
|
||||
.name = "Deep-Buffer Audio Port",
|
||||
.stream_name = "Deep-Buffer Audio",
|
||||
.cpu_dai_name = "deepbuffer-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.nonatomic = true,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_COMPR] = {
|
||||
.name = "Compressed Port",
|
||||
.stream_name = "Compress",
|
||||
.cpu_dai_name = "compress-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
},
|
||||
/* CODEC<->CODEC link */
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "da7213-hifi",
|
||||
.codec_name = "i2c-DLGS7213:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.be_hw_params_fixup = codec_fixup,
|
||||
.nonatomic = true,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &ssp2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
static struct snd_soc_card bytcht_da7213_card = {
|
||||
.name = "bytcht-da7213",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = dailink,
|
||||
.num_links = ARRAY_SIZE(dailink),
|
||||
.controls = controls,
|
||||
.num_controls = ARRAY_SIZE(controls),
|
||||
.dapm_widgets = dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
|
||||
.dapm_routes = audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(audio_map),
|
||||
};
|
||||
|
||||
static char codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
|
||||
static int bytcht_da7213_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
int i;
|
||||
struct snd_soc_card *card;
|
||||
struct sst_acpi_mach *mach;
|
||||
const char *i2c_name = NULL;
|
||||
int dai_index = 0;
|
||||
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
card = &bytcht_da7213_card;
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
/* fix index of codec dai */
|
||||
dai_index = MERR_DPCM_COMPR + 1;
|
||||
for (i = 0; i < ARRAY_SIZE(dailink); i++) {
|
||||
if (!strcmp(dailink[i].codec_name, "i2c-DLGS7213:00")) {
|
||||
dai_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = sst_acpi_find_name_from_hid(mach->id);
|
||||
if (i2c_name != NULL) {
|
||||
snprintf(codec_name, sizeof(codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
dailink[dai_index].codec_name = codec_name;
|
||||
}
|
||||
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_card failed %d\n", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
platform_set_drvdata(pdev, card);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static struct platform_driver bytcht_da7213_driver = {
|
||||
.driver = {
|
||||
.name = "bytcht_da7213",
|
||||
},
|
||||
.probe = bytcht_da7213_probe,
|
||||
};
|
||||
module_platform_driver(bytcht_da7213_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail+DA7213 Machine driver");
|
||||
MODULE_AUTHOR("Pierre-Louis Bossart");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bytcht_da7213");
|
208
sound/soc/intel/boards/bytcht_nocodec.c
Normal file
208
sound/soc/intel/boards/bytcht_nocodec.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* bytcht_nocodec.c - ASoc Machine driver for MinnowBoard Max and Up
|
||||
* to make I2S signals observable on the Low-Speed connector. Audio codec
|
||||
* is not managed by ASoC/DAPM
|
||||
*
|
||||
* Copyright (C) 2015-2017 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/module.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include "../atom/sst-atom-controls.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget widgets[] = {
|
||||
SND_SOC_DAPM_MIC("Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map[] = {
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx"},
|
||||
{"codec_in1", NULL, "ssp2 Rx"},
|
||||
|
||||
{"ssp2 Rx", NULL, "Mic"},
|
||||
{"Speaker", NULL, "ssp2 Tx"},
|
||||
};
|
||||
|
||||
static int codec_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);
|
||||
int ret;
|
||||
|
||||
/* The DSP will convert the FE rate to 48k, stereo, 24bits */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot, override config
|
||||
* with explicit setting to I2S 2ch 24-bit. The word length is set with
|
||||
* dai_set_tdm_slot() since there is no other API exposed
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int rates_48000[] = {
|
||||
48000,
|
||||
};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list constraints_48000 = {
|
||||
.count = ARRAY_SIZE(rates_48000),
|
||||
.list = rates_48000,
|
||||
};
|
||||
|
||||
static int aif1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_48000);
|
||||
}
|
||||
|
||||
static struct snd_soc_ops aif1_ops = {
|
||||
.startup = aif1_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link dais[] = {
|
||||
[MERR_DPCM_AUDIO] = {
|
||||
.name = "Audio Port",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "media-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = true,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_DEEP_BUFFER] = {
|
||||
.name = "Deep-Buffer Audio Port",
|
||||
.stream_name = "Deep-Buffer Audio",
|
||||
.cpu_dai_name = "deepbuffer-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = true,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_COMPR] = {
|
||||
.name = "Compressed Port",
|
||||
.stream_name = "Compress",
|
||||
.cpu_dai_name = "compress-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
},
|
||||
/* CODEC<->CODEC link */
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-LowSpeed Connector",
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.be_hw_params_fixup = codec_fixup,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = true,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
static struct snd_soc_card bytcht_nocodec_card = {
|
||||
.name = "bytcht-nocodec",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = dais,
|
||||
.num_links = ARRAY_SIZE(dais),
|
||||
.dapm_widgets = widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(widgets),
|
||||
.dapm_routes = audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(audio_map),
|
||||
.controls = controls,
|
||||
.num_controls = ARRAY_SIZE(controls),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int snd_bytcht_nocodec_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
/* register the soc card */
|
||||
bytcht_nocodec_card.dev = &pdev->dev;
|
||||
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &bytcht_nocodec_card);
|
||||
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
|
||||
ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
platform_set_drvdata(pdev, &bytcht_nocodec_card);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static struct platform_driver snd_bytcht_nocodec_mc_driver = {
|
||||
.driver = {
|
||||
.name = "bytcht_nocodec",
|
||||
},
|
||||
.probe = snd_bytcht_nocodec_mc_probe,
|
||||
};
|
||||
module_platform_driver(snd_bytcht_nocodec_mc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Nocodec Machine driver");
|
||||
MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bytcht_nocodec");
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
@ -56,35 +57,88 @@ enum {
|
||||
struct byt_rt5640_private {
|
||||
struct clk *mclk;
|
||||
};
|
||||
static bool is_bytcr;
|
||||
|
||||
static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN;
|
||||
static unsigned int quirk_override;
|
||||
module_param_named(quirk, quirk_override, uint, 0444);
|
||||
MODULE_PARM_DESC(quirk, "Board-specific quirk override");
|
||||
|
||||
static void log_quirks(struct device *dev)
|
||||
{
|
||||
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP)
|
||||
dev_info(dev, "quirk DMIC1_MAP enabled");
|
||||
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP)
|
||||
dev_info(dev, "quirk DMIC2_MAP enabled");
|
||||
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP)
|
||||
dev_info(dev, "quirk IN1_MAP enabled");
|
||||
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP)
|
||||
dev_info(dev, "quirk IN3_MAP enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN)
|
||||
dev_info(dev, "quirk DMIC enabled");
|
||||
int map;
|
||||
bool has_dmic = false;
|
||||
bool has_mclk = false;
|
||||
bool has_ssp0 = false;
|
||||
bool has_ssp0_aif1 = false;
|
||||
bool has_ssp0_aif2 = false;
|
||||
bool has_ssp2_aif2 = false;
|
||||
|
||||
map = BYT_RT5640_MAP(byt_rt5640_quirk);
|
||||
switch (map) {
|
||||
case BYT_RT5640_DMIC1_MAP:
|
||||
dev_info(dev, "quirk DMIC1_MAP enabled\n");
|
||||
has_dmic = true;
|
||||
break;
|
||||
case BYT_RT5640_DMIC2_MAP:
|
||||
dev_info(dev, "quirk DMIC2_MAP enabled\n");
|
||||
has_dmic = true;
|
||||
break;
|
||||
case BYT_RT5640_IN1_MAP:
|
||||
dev_info(dev, "quirk IN1_MAP enabled\n");
|
||||
break;
|
||||
case BYT_RT5640_IN3_MAP:
|
||||
dev_info(dev, "quirk IN3_MAP enabled\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
|
||||
break;
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
|
||||
if (has_dmic)
|
||||
dev_info(dev, "quirk DMIC enabled\n");
|
||||
else
|
||||
dev_err(dev, "quirk DMIC enabled but no DMIC input set, will be ignored\n");
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
|
||||
dev_info(dev, "quirk MONO_SPEAKER enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
|
||||
dev_info(dev, "quirk DIFF_MIC enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2)
|
||||
dev_info(dev, "quirk SSP2_AIF2 enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1)
|
||||
dev_info(dev, "quirk SSP0_AIF1 enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)
|
||||
dev_info(dev, "quirk SSP0_AIF2 enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
|
||||
dev_info(dev, "quirk MCLK_EN enabled");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
|
||||
dev_info(dev, "quirk MCLK_25MHZ enabled");
|
||||
dev_info(dev, "quirk MONO_SPEAKER enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
|
||||
if (!has_dmic)
|
||||
dev_info(dev, "quirk DIFF_MIC enabled\n");
|
||||
else
|
||||
dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\n");
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
|
||||
dev_info(dev, "quirk SSP0_AIF1 enabled\n");
|
||||
has_ssp0 = true;
|
||||
has_ssp0_aif1 = true;
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) {
|
||||
dev_info(dev, "quirk SSP0_AIF2 enabled\n");
|
||||
has_ssp0 = true;
|
||||
has_ssp0_aif2 = true;
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) {
|
||||
dev_info(dev, "quirk SSP2_AIF2 enabled\n");
|
||||
has_ssp2_aif2 = true;
|
||||
}
|
||||
if (is_bytcr && !has_ssp0)
|
||||
dev_err(dev, "Invalid routing, bytcr detected but no SSP0-based quirk, audio cannot work with SSP2 on bytcr\n");
|
||||
if (has_ssp0_aif1 && has_ssp0_aif2)
|
||||
dev_err(dev, "Invalid routing, SSP0 cannot be connected to both AIF1 and AIF2\n");
|
||||
if (has_ssp0 && has_ssp2_aif2)
|
||||
dev_err(dev, "Invalid routing, cannot have both SSP0 and SSP2 connected to codec\n");
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
|
||||
dev_info(dev, "quirk MCLK_EN enabled\n");
|
||||
has_mclk = true;
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
|
||||
if (has_mclk)
|
||||
dev_info(dev, "quirk MCLK_25MHZ enabled\n");
|
||||
else
|
||||
dev_err(dev, "quirk MCLK_25MHZ enabled but quirk MCLK not selected, will be ignored\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -128,7 +182,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
ret = clk_prepare_enable(priv->mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev,
|
||||
"could not configure MCLK state");
|
||||
"could not configure MCLK state\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -710,8 +764,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
||||
int i;
|
||||
int dai_index;
|
||||
struct byt_rt5640_private *priv;
|
||||
bool is_bytcr = false;
|
||||
|
||||
is_bytcr = false;
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
@ -806,6 +860,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
||||
|
||||
/* check quirks before creating card */
|
||||
dmi_check_system(byt_rt5640_quirk_table);
|
||||
if (quirk_override) {
|
||||
dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",
|
||||
(unsigned int)byt_rt5640_quirk, quirk_override);
|
||||
byt_rt5640_quirk = quirk_override;
|
||||
}
|
||||
log_quirks(&pdev->dev);
|
||||
|
||||
if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
|
||||
|
@ -2000,10 +2000,8 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw,
|
||||
u32 param_size, char *param)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *data = NULL;
|
||||
u32 header = 0;
|
||||
u32 payload_size = 0, transfer_parameter_size = 0;
|
||||
dma_addr_t dma_addr = 0;
|
||||
struct sst_hsw_transfer_parameter *parameter;
|
||||
struct device *dev = hsw->dev;
|
||||
|
||||
@ -2047,10 +2045,6 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw,
|
||||
|
||||
kfree(parameter);
|
||||
|
||||
if (data)
|
||||
dma_free_coherent(hsw->dsp->dma_dev,
|
||||
param_size, (void *)data, dma_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,8 @@
|
||||
#include "skl-sst-ipc.h"
|
||||
|
||||
#define BXT_BASEFW_TIMEOUT 3000
|
||||
#define BXT_INIT_TIMEOUT 500
|
||||
#define BXT_INIT_TIMEOUT 300
|
||||
#define BXT_ROM_INIT_TIMEOUT 70
|
||||
#define BXT_IPC_PURGE_FW 0x01004000
|
||||
|
||||
#define BXT_ROM_INIT 0x5
|
||||
@ -45,6 +46,8 @@
|
||||
/* Delay before scheduling D0i3 entry */
|
||||
#define BXT_D0I3_DELAY 5000
|
||||
|
||||
#define BXT_FW_ROM_INIT_RETRY 3
|
||||
|
||||
static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
|
||||
{
|
||||
return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
|
||||
@ -55,29 +58,15 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
|
||||
{
|
||||
struct snd_dma_buffer dmab;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
const struct firmware *fw = NULL;
|
||||
struct firmware stripped_fw;
|
||||
int ret = 0, i, dma_id, stream_tag;
|
||||
|
||||
/* library indices start from 1 to N. 0 represents base FW */
|
||||
for (i = 1; i < lib_count; i++) {
|
||||
ret = request_firmware(&fw, linfo[i].name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request lib %s failed:%d\n",
|
||||
linfo[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (skl->is_first_boot) {
|
||||
ret = snd_skl_parse_uuids(ctx, fw,
|
||||
ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
|
||||
BXT_ADSP_FW_BIN_HDR_OFFSET, i);
|
||||
if (ret < 0)
|
||||
goto load_library_failed;
|
||||
}
|
||||
|
||||
stripped_fw.data = fw->data;
|
||||
stripped_fw.size = fw->size;
|
||||
skl_dsp_strip_extended_manifest(&stripped_fw);
|
||||
if (ret < 0)
|
||||
goto load_library_failed;
|
||||
|
||||
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40,
|
||||
stripped_fw.size, &dmab);
|
||||
@ -92,21 +81,19 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
|
||||
memcpy(dmab.area, stripped_fw.data, stripped_fw.size);
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, true, stream_tag);
|
||||
ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i);
|
||||
ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
|
||||
linfo[i].name, ret);
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
|
||||
ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
|
||||
release_firmware(fw);
|
||||
fw = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
load_library_failed:
|
||||
release_firmware(fw);
|
||||
skl_release_library(linfo, lib_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -156,7 +143,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
BXT_INIT_TIMEOUT, "HIPCIE Done");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timout for Purge Request%d\n", ret);
|
||||
dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
@ -173,7 +160,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
||||
|
||||
/* Step 7: Wait for ROM init */
|
||||
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
|
||||
SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load");
|
||||
SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
@ -206,18 +193,16 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
|
||||
{
|
||||
struct firmware stripped_fw;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
if (ctx->fw == NULL) {
|
||||
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for extended manifest */
|
||||
if (ctx->fw == NULL)
|
||||
goto sst_load_base_firmware_failed;
|
||||
|
||||
/* prase uuids on first boot */
|
||||
if (skl->is_first_boot) {
|
||||
ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0);
|
||||
@ -229,18 +214,20 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
|
||||
stripped_fw.size = ctx->fw->size;
|
||||
skl_dsp_strip_extended_manifest(&stripped_fw);
|
||||
|
||||
ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
|
||||
/* Retry Enabling core and ROM load. Retry seemed to help */
|
||||
if (ret < 0) {
|
||||
|
||||
for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) {
|
||||
ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
|
||||
|
||||
dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
|
||||
ret = sst_transfer_fw_host_dma(ctx);
|
||||
@ -265,8 +252,11 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
sst_load_base_firmware_failed:
|
||||
release_firmware(ctx->fw);
|
||||
ctx->fw = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -428,6 +418,7 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
skl->cores.state[core_id] = SKL_DSP_RUNNING;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -514,11 +505,22 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
|
||||
|
||||
ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
|
||||
BXT_BASE_FW_MODULE_ID, &dx);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev,
|
||||
"Failed to set DSP to D3:core id = %d;Continue reset\n",
|
||||
core_id);
|
||||
/*
|
||||
* In case of D3 failure, re-download the firmware, so set
|
||||
* fw_loaded to false.
|
||||
*/
|
||||
skl->fw_loaded = false;
|
||||
}
|
||||
|
||||
if (core_id == SKL_DSP_CORE0_ID) {
|
||||
/* disable Interrupt */
|
||||
skl_ipc_op_int_disable(ctx);
|
||||
skl_ipc_int_disable(ctx);
|
||||
}
|
||||
ret = skl_dsp_disable_core(ctx, core_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to disable core %d\n", ret);
|
||||
@ -560,23 +562,14 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
struct sst_dsp *sst;
|
||||
int ret;
|
||||
|
||||
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
|
||||
if (skl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
skl->dev = dev;
|
||||
skl_dev.thread_context = skl;
|
||||
INIT_LIST_HEAD(&skl->uuid_list);
|
||||
|
||||
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
dev_err(skl->dev, "skl_dsp_ctx_init failed\n");
|
||||
return -ENODEV;
|
||||
ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: no device\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skl = *dsp;
|
||||
sst = skl->dsp;
|
||||
sst->fw_name = fw_name;
|
||||
sst->dsp_ops = dsp_ops;
|
||||
sst->fw_ops = bxt_fw_ops;
|
||||
sst->addr.lpe = mmio_base;
|
||||
sst->addr.shim = mmio_base;
|
||||
@ -584,24 +577,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
|
||||
SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
|
||||
|
||||
INIT_LIST_HEAD(&sst->module_list);
|
||||
ret = skl_ipc_init(dev, skl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* set the D0i3 check */
|
||||
skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
|
||||
|
||||
skl->cores.count = 2;
|
||||
skl->boot_complete = false;
|
||||
init_waitqueue_head(&skl->boot_wait);
|
||||
skl->is_first_boot = true;
|
||||
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
|
||||
skl->d0i3.state = SKL_DSP_D0I3_NONE;
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
|
||||
@ -635,6 +619,10 @@ EXPORT_SYMBOL_GPL(bxt_sst_init_fw);
|
||||
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
|
||||
skl_release_library(ctx->lib_info, ctx->lib_count);
|
||||
if (ctx->dsp->fw)
|
||||
release_firmware(ctx->dsp->fw);
|
||||
skl_freeup_uuid_list(ctx);
|
||||
skl_ipc_free(&ctx->ipc);
|
||||
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
|
||||
|
@ -58,7 +58,7 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
|
||||
#define NOTIFICATION_MASK 0xf
|
||||
|
||||
/* disable notfication for underruns/overruns from firmware module */
|
||||
static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
|
||||
void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
|
||||
{
|
||||
struct notification_mask mask;
|
||||
struct skl_ipc_large_config_msg msg = {0};
|
||||
@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
|
||||
{
|
||||
.id = 0x9d71,
|
||||
.loader_ops = skl_get_loader_ops,
|
||||
.init = skl_sst_dsp_init,
|
||||
.init = kbl_sst_dsp_init,
|
||||
.init_fw = skl_sst_init_fw,
|
||||
.cleanup = skl_sst_dsp_cleanup
|
||||
},
|
||||
@ -274,6 +274,7 @@ int skl_init_dsp(struct skl *skl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
skl->skl_sst->dsp_ops = ops;
|
||||
dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
@ -284,16 +285,11 @@ int skl_free_dsp(struct skl *skl)
|
||||
struct hdac_ext_bus *ebus = &skl->ebus;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
const struct skl_dsp_ops *ops;
|
||||
|
||||
/* disable ppcap interrupt */
|
||||
snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
|
||||
|
||||
ops = skl_get_dsp_ops(skl->pci->device);
|
||||
if (!ops)
|
||||
return -EIO;
|
||||
|
||||
ops->cleanup(bus->dev, ctx);
|
||||
ctx->dsp_ops->cleanup(bus->dev, ctx);
|
||||
|
||||
if (ctx->dsp->addr.lpe)
|
||||
iounmap(ctx->dsp->addr.lpe);
|
||||
@ -866,7 +862,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
|
||||
}
|
||||
|
||||
if (!found)
|
||||
mcfg->m_state = SKL_MODULE_UNINIT;
|
||||
mcfg->m_state = SKL_MODULE_INIT_DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1098,7 +1094,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
|
||||
dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
|
||||
|
||||
/* If pipe is started, do stop the pipe in FW. */
|
||||
if (pipe->state > SKL_PIPE_STARTED) {
|
||||
if (pipe->state >= SKL_PIPE_STARTED) {
|
||||
ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to stop pipeline\n");
|
||||
|
@ -24,8 +24,6 @@
|
||||
static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
|
||||
0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53};
|
||||
|
||||
#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
|
||||
|
||||
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
|
||||
{
|
||||
acpi_handle handle;
|
||||
@ -33,8 +31,9 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
|
||||
struct nhlt_resource_desc *nhlt_ptr = NULL;
|
||||
struct nhlt_acpi_table *nhlt_table = NULL;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) {
|
||||
dev_err(dev, "Requested NHLT device not found\n");
|
||||
handle = ACPI_HANDLE(dev);
|
||||
if (!handle) {
|
||||
dev_err(dev, "Didn't find ACPI_HANDLE\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include "skl.h"
|
||||
@ -155,7 +156,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 32, 0);
|
||||
params->ch, params->format, params->host_bps, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
@ -190,8 +191,8 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
|
||||
stream = stream_to_hdac_ext_stream(hstream);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 24, 0);
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
|
||||
params->format, params->link_bps, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
@ -262,23 +263,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_be_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_module_cfg *mconfig;
|
||||
|
||||
if (dai->playback_widget->power || dai->capture_widget->power)
|
||||
return 0;
|
||||
|
||||
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
|
||||
if (mconfig == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return skl_dsp_set_dma_control(ctx, mconfig);
|
||||
}
|
||||
|
||||
static int skl_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -326,6 +310,11 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
p_params.host_dma_id = dma_id;
|
||||
p_params.stream = substream->stream;
|
||||
p_params.format = params_format(params);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
p_params.host_bps = dai->driver->playback.sig_bits;
|
||||
else
|
||||
p_params.host_bps = dai->driver->capture.sig_bits;
|
||||
|
||||
|
||||
m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
|
||||
if (m_cfg)
|
||||
@ -564,6 +553,11 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
||||
p_params.link_index = link->index;
|
||||
p_params.format = params_format(params);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
p_params.link_bps = codec_dai->driver->playback.sig_bits;
|
||||
else
|
||||
p_params.link_bps = codec_dai->driver->capture.sig_bits;
|
||||
|
||||
return skl_tplg_be_update_params(dai, &p_params);
|
||||
}
|
||||
|
||||
@ -649,7 +643,6 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = {
|
||||
|
||||
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
|
||||
.hw_params = skl_be_hw_params,
|
||||
.prepare = skl_be_prepare,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops skl_link_dai_ops = {
|
||||
@ -670,6 +663,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "System Capture",
|
||||
@ -677,6 +671,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -688,6 +683,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.channels_max = HDA_QUAD,
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -699,6 +695,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -710,6 +707,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -721,6 +719,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.channels_max = HDA_QUAD,
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -736,6 +735,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -751,6 +751,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -766,6 +767,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 32,
|
||||
},
|
||||
},
|
||||
|
||||
@ -949,14 +951,12 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
|
||||
static int skl_platform_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
|
||||
dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__,
|
||||
dai_link->cpu_dai_name);
|
||||
|
||||
runtime = substream->runtime;
|
||||
snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw);
|
||||
|
||||
return 0;
|
||||
@ -1062,13 +1062,31 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
|
||||
* HAD space reflects the actual data that is transferred.
|
||||
* Use the position buffer for capture, as DPIB write gets
|
||||
* completed earlier than the actual data written to the DDR.
|
||||
*
|
||||
* For capture stream following workaround is required to fix the
|
||||
* incorrect position reporting.
|
||||
*
|
||||
* 1. Wait for 20us before reading the DMA position in buffer once
|
||||
* the interrupt is generated for stream completion as update happens
|
||||
* on the HDA frame boundary i.e. 20.833uSec.
|
||||
* 2. Read DPIB register to flush the DMA position value. This dummy
|
||||
* read is required to flush DMA position value.
|
||||
* 3. Read the DMA Position-in-Buffer. This value now will be equal to
|
||||
* or greater than period boundary.
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hdac_stream(hstream)->index));
|
||||
else
|
||||
} else {
|
||||
udelay(20);
|
||||
readl(ebus->bus.remap_addr +
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hdac_stream(hstream)->index));
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
|
||||
}
|
||||
|
||||
if (pos >= hdac_stream(hstream)->bufsize)
|
||||
pos = 0;
|
||||
@ -1165,7 +1183,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
snd_dma_pci_data(skl->pci),
|
||||
size, MAX_PREALLOC_SIZE);
|
||||
if (retval) {
|
||||
dev_err(dai->dev, "dma buffer allocationf fail\n");
|
||||
dev_err(dai->dev, "dma buffer allocation fail\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@ -1173,29 +1191,52 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
|
||||
{
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct uuid_module *module;
|
||||
uuid_le *uuid_mod;
|
||||
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
|
||||
if (list_empty(&ctx->uuid_list)) {
|
||||
dev_err(ctx->dev, "Module list is empty\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
list_for_each_entry(module, &ctx->uuid_list, list) {
|
||||
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
|
||||
mconfig->id.module_id = module->id;
|
||||
mconfig->is_loadable = module->is_loadable;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int skl_populate_modules(struct skl *skl)
|
||||
{
|
||||
struct skl_pipeline *p;
|
||||
struct skl_pipe_module *m;
|
||||
struct snd_soc_dapm_widget *w;
|
||||
struct skl_module_cfg *mconfig;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(p, &skl->ppl_list, node) {
|
||||
list_for_each_entry(m, &p->pipe->w_list, node) {
|
||||
|
||||
w = m->w;
|
||||
mconfig = w->priv;
|
||||
|
||||
ret = snd_skl_get_module_info(skl->skl_sst, mconfig);
|
||||
ret = skl_get_module_info(skl, mconfig);
|
||||
if (ret < 0) {
|
||||
dev_err(skl->skl_sst->dev,
|
||||
"query module info failed:%d\n", ret);
|
||||
goto err;
|
||||
"query module info failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1232,6 +1273,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
||||
}
|
||||
skl_populate_modules(skl);
|
||||
skl->skl_sst->update_d0i3c = skl_update_d0i3c;
|
||||
skl_dsp_enable_notification(skl->skl_sst, false);
|
||||
}
|
||||
pm_runtime_mark_last_busy(platform->dev);
|
||||
pm_runtime_put_autosuspend(platform->dev);
|
||||
@ -1256,6 +1298,7 @@ int skl_platform_register(struct device *dev)
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
|
||||
INIT_LIST_HEAD(&skl->ppl_list);
|
||||
INIT_LIST_HEAD(&skl->bind_list);
|
||||
|
||||
ret = snd_soc_register_platform(dev, &skl_platform_drv);
|
||||
if (ret) {
|
||||
@ -1276,6 +1319,17 @@ int skl_platform_register(struct device *dev)
|
||||
|
||||
int skl_platform_unregister(struct device *dev)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct skl_module_deferred_bind *modules, *tmp;
|
||||
|
||||
if (!list_empty(&skl->bind_list)) {
|
||||
list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
|
||||
list_del(&modules->node);
|
||||
kfree(modules);
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_unregister_component(dev);
|
||||
snd_soc_unregister_platform(dev);
|
||||
return 0;
|
||||
|
@ -164,7 +164,7 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx)
|
||||
ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
|
||||
}
|
||||
|
||||
static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
|
||||
int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -243,9 +243,14 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
|
||||
* 2. Polling on fw register to identify if data left to transferred doesn't
|
||||
* fill the ring buffer. Caller takes care of polling the required status
|
||||
* register to identify the transfer status.
|
||||
* 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till
|
||||
* bytes_left is 0.
|
||||
* if wait flag is not set, doesn't wait for BDL interrupt. after ccopying
|
||||
* the first chunk return the no of bytes_left to be copied.
|
||||
*/
|
||||
static int
|
||||
skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
|
||||
skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin,
|
||||
u32 total_size, bool wait)
|
||||
{
|
||||
int ret = 0;
|
||||
bool start = true;
|
||||
@ -272,13 +277,14 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
|
||||
size = ctx->cl_dev.bufsize;
|
||||
skl_cldma_fill_buffer(ctx, size, curr_pos, true, start);
|
||||
|
||||
start = false;
|
||||
ret = skl_cldma_wait_interruptible(ctx);
|
||||
if (ret < 0) {
|
||||
skl_cldma_stop(ctx);
|
||||
return ret;
|
||||
if (wait) {
|
||||
start = false;
|
||||
ret = skl_cldma_wait_interruptible(ctx);
|
||||
if (ret < 0) {
|
||||
skl_cldma_stop(ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
skl_cldma_int_disable(ctx);
|
||||
|
||||
@ -298,9 +304,11 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
|
||||
}
|
||||
bytes_left -= size;
|
||||
curr_pos = curr_pos + size;
|
||||
if (!wait)
|
||||
return bytes_left;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return bytes_left;
|
||||
}
|
||||
|
||||
void skl_cldma_process_intr(struct sst_dsp *ctx)
|
||||
|
@ -213,7 +213,7 @@ struct skl_cl_dev_ops {
|
||||
void (*cl_trigger)(struct sst_dsp *ctx, bool enable);
|
||||
void (*cl_cleanup_controller)(struct sst_dsp *ctx);
|
||||
int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx,
|
||||
const void *bin, u32 size);
|
||||
const void *bin, u32 size, bool wait);
|
||||
void (*cl_stop_dma)(struct sst_dsp *ctx);
|
||||
};
|
||||
|
||||
|
@ -355,12 +355,13 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
|
||||
ret = ctx->fw_ops.set_state_D0(ctx, core_id);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "unable to get core%d\n", core_id);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
skl->cores.usage_count[core_id]++;
|
||||
|
||||
out:
|
||||
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
|
||||
core_id, skl->cores.state[core_id],
|
||||
skl->cores.usage_count[core_id]);
|
||||
@ -379,7 +380,8 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (--skl->cores.usage_count[core_id] == 0) {
|
||||
if ((--skl->cores.usage_count[core_id] == 0) &&
|
||||
(skl->cores.state[core_id] != SKL_DSP_RESET)) {
|
||||
ret = ctx->fw_ops.set_state_D3(ctx, core_id);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "unable to put core %d: %d\n",
|
||||
|
@ -17,13 +17,15 @@
|
||||
#define __SKL_SST_DSP_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/memalloc.h>
|
||||
#include "skl-sst-cldma.h"
|
||||
#include "skl-topology.h"
|
||||
|
||||
struct sst_dsp;
|
||||
struct skl_sst;
|
||||
struct sst_dsp_device;
|
||||
struct skl_lib_info;
|
||||
|
||||
/* Intel HD Audio General DSP Registers */
|
||||
#define SKL_ADSP_GEN_BASE 0x0
|
||||
@ -144,7 +146,7 @@ struct skl_dsp_fw_ops {
|
||||
int (*load_fw)(struct sst_dsp *ctx);
|
||||
/* FW module parser/loader */
|
||||
int (*load_library)(struct sst_dsp *ctx,
|
||||
struct skl_lib_info *linfo, int count);
|
||||
struct skl_lib_info *linfo, int lib_count);
|
||||
int (*parse_fw)(struct sst_dsp *ctx);
|
||||
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
@ -172,6 +174,19 @@ struct skl_dsp_loader_ops {
|
||||
int stream_tag);
|
||||
};
|
||||
|
||||
#define MAX_INSTANCE_BUFF 2
|
||||
|
||||
struct uuid_module {
|
||||
uuid_le uuid;
|
||||
int id;
|
||||
int is_loadable;
|
||||
int max_instance;
|
||||
u64 pvt_id[MAX_INSTANCE_BUFF];
|
||||
int *instance_id;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct skl_load_module_info {
|
||||
u16 mod_id;
|
||||
const struct firmware *fw;
|
||||
@ -186,6 +201,7 @@ struct skl_module_table {
|
||||
void skl_cldma_process_intr(struct sst_dsp *ctx);
|
||||
void skl_cldma_int_disable(struct sst_dsp *ctx);
|
||||
int skl_cldma_prepare(struct sst_dsp *ctx);
|
||||
int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
|
||||
|
||||
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
|
||||
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
|
||||
@ -214,6 +230,9 @@ int skl_dsp_boot(struct sst_dsp *ctx);
|
||||
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp);
|
||||
int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp);
|
||||
int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp);
|
||||
@ -222,17 +241,22 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx);
|
||||
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
|
||||
|
||||
int snd_skl_get_module_info(struct skl_sst *ctx,
|
||||
struct skl_module_cfg *mconfig);
|
||||
int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
|
||||
unsigned int offset, int index);
|
||||
int skl_get_pvt_id(struct skl_sst *ctx,
|
||||
struct skl_module_cfg *mconfig);
|
||||
int skl_put_pvt_id(struct skl_sst *ctx,
|
||||
struct skl_module_cfg *mconfig);
|
||||
int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id);
|
||||
int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id);
|
||||
int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
|
||||
int module_id, int instance_id);
|
||||
void skl_freeup_uuid_list(struct skl_sst *ctx);
|
||||
|
||||
int skl_dsp_strip_extended_manifest(struct firmware *fw);
|
||||
void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable);
|
||||
int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
|
||||
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
|
||||
struct sst_dsp_device *skl_dev);
|
||||
int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
|
||||
struct firmware *stripped_fw,
|
||||
unsigned int hdr_offset, int index);
|
||||
void skl_release_library(struct skl_lib_info *linfo, int lib_count);
|
||||
|
||||
#endif /*__SKL_SST_DSP_H__*/
|
||||
|
@ -34,6 +34,11 @@
|
||||
#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1)
|
||||
#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT)
|
||||
|
||||
#define IPC_GLB_REPLY_TYPE_SHIFT 29
|
||||
#define IPC_GLB_REPLY_TYPE_MASK 0x1F
|
||||
#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \
|
||||
& IPC_GLB_RPLY_TYPE_MASK)
|
||||
|
||||
#define IPC_TIMEOUT_MSECS 3000
|
||||
|
||||
#define IPC_EMPTY_LIST_SIZE 8
|
||||
@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_ipc_set_reply_error_code(u32 reply)
|
||||
{
|
||||
switch (reply) {
|
||||
case IPC_GLB_REPLY_OUT_OF_MEMORY:
|
||||
return -ENOMEM;
|
||||
|
||||
case IPC_GLB_REPLY_BUSY:
|
||||
return -EBUSY;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
|
||||
struct skl_ipc_header header)
|
||||
{
|
||||
struct ipc_message *msg;
|
||||
u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
|
||||
u64 *ipc_header = (u64 *)(&header);
|
||||
struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
|
||||
|
||||
msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
|
||||
if (msg == NULL) {
|
||||
@ -401,33 +421,39 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
|
||||
}
|
||||
|
||||
/* first process the header */
|
||||
switch (reply) {
|
||||
case IPC_GLB_REPLY_SUCCESS:
|
||||
if (reply == IPC_GLB_REPLY_SUCCESS) {
|
||||
dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary);
|
||||
/* copy the rx data from the mailbox */
|
||||
sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
|
||||
break;
|
||||
switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
|
||||
case IPC_GLB_LOAD_MULTIPLE_MODS:
|
||||
case IPC_GLB_LOAD_LIBRARY:
|
||||
skl->mod_load_complete = true;
|
||||
skl->mod_load_status = true;
|
||||
wake_up(&skl->mod_load_wait);
|
||||
break;
|
||||
|
||||
case IPC_GLB_REPLY_OUT_OF_MEMORY:
|
||||
dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary);
|
||||
msg->errno = -ENOMEM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
case IPC_GLB_REPLY_BUSY:
|
||||
dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary);
|
||||
msg->errno = -EBUSY;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply);
|
||||
msg->errno = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply != IPC_GLB_REPLY_SUCCESS) {
|
||||
}
|
||||
} else {
|
||||
msg->errno = skl_ipc_set_reply_error_code(reply);
|
||||
dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
|
||||
dev_err(ipc->dev, "FW Error Code: %u\n",
|
||||
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
|
||||
switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
|
||||
case IPC_GLB_LOAD_MULTIPLE_MODS:
|
||||
case IPC_GLB_LOAD_LIBRARY:
|
||||
skl->mod_load_complete = true;
|
||||
skl->mod_load_status = false;
|
||||
wake_up(&skl->mod_load_wait);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
list_del(&msg->list);
|
||||
@ -811,8 +837,8 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
|
||||
header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
|
||||
header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
|
||||
|
||||
ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
|
||||
(sizeof(u16) * module_cnt), NULL, 0);
|
||||
ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data,
|
||||
(sizeof(u16) * module_cnt));
|
||||
if (ret < 0)
|
||||
dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
|
||||
|
||||
@ -947,7 +973,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
|
||||
EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
|
||||
|
||||
int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
|
||||
u8 dma_id, u8 table_id)
|
||||
u8 dma_id, u8 table_id, bool wait)
|
||||
{
|
||||
struct skl_ipc_header header = {0};
|
||||
u64 *ipc_header = (u64 *)(&header);
|
||||
@ -959,7 +985,11 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
|
||||
header.primary |= IPC_MOD_INSTANCE_ID(table_id);
|
||||
header.primary |= IPC_MOD_ID(dma_id);
|
||||
|
||||
ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
|
||||
if (wait)
|
||||
ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
|
||||
NULL, 0, NULL, 0);
|
||||
else
|
||||
ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, NULL, 0);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(ipc->dev, "ipc: load lib failed\n");
|
||||
|
@ -69,6 +69,14 @@ struct skl_d0i3_data {
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
#define SKL_LIB_NAME_LENGTH 128
|
||||
#define SKL_MAX_LIB 16
|
||||
|
||||
struct skl_lib_info {
|
||||
char name[SKL_LIB_NAME_LENGTH];
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
struct skl_sst {
|
||||
struct device *dev;
|
||||
struct sst_dsp *dsp;
|
||||
@ -77,6 +85,11 @@ struct skl_sst {
|
||||
wait_queue_head_t boot_wait;
|
||||
bool boot_complete;
|
||||
|
||||
/* module load */
|
||||
wait_queue_head_t mod_load_wait;
|
||||
bool mod_load_complete;
|
||||
bool mod_load_status;
|
||||
|
||||
/* IPC messaging */
|
||||
struct sst_generic_ipc ipc;
|
||||
|
||||
@ -105,6 +118,8 @@ struct skl_sst {
|
||||
void (*update_d0i3c)(struct device *dev, bool enable);
|
||||
|
||||
struct skl_d0i3_data d0i3;
|
||||
|
||||
const struct skl_dsp_ops *dsp_ops;
|
||||
};
|
||||
|
||||
struct skl_ipc_init_instance_msg {
|
||||
@ -182,7 +197,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
|
||||
struct skl_ipc_large_config_msg *msg, u32 *param);
|
||||
|
||||
int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
|
||||
u8 dma_id, u8 table_id);
|
||||
u8 dma_id, u8 table_id, bool wait);
|
||||
|
||||
int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
|
||||
struct skl_ipc_d0ix_msg *msg);
|
||||
|
@ -94,19 +94,6 @@ struct adsp_fw_hdr {
|
||||
u32 load_offset;
|
||||
} __packed;
|
||||
|
||||
#define MAX_INSTANCE_BUFF 2
|
||||
|
||||
struct uuid_module {
|
||||
uuid_le uuid;
|
||||
int id;
|
||||
int is_loadable;
|
||||
int max_instance;
|
||||
u64 pvt_id[MAX_INSTANCE_BUFF];
|
||||
int *instance_id;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct skl_ext_manifest_hdr {
|
||||
u32 id;
|
||||
u32 len;
|
||||
@ -115,32 +102,6 @@ struct skl_ext_manifest_hdr {
|
||||
u32 entries;
|
||||
};
|
||||
|
||||
int snd_skl_get_module_info(struct skl_sst *ctx,
|
||||
struct skl_module_cfg *mconfig)
|
||||
{
|
||||
struct uuid_module *module;
|
||||
uuid_le *uuid_mod;
|
||||
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
|
||||
if (list_empty(&ctx->uuid_list)) {
|
||||
dev_err(ctx->dev, "Module list is empty\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(module, &ctx->uuid_list, list) {
|
||||
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
|
||||
mconfig->id.module_id = module->id;
|
||||
mconfig->is_loadable = module->is_loadable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_skl_get_module_info);
|
||||
|
||||
static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
|
||||
{
|
||||
int pvt_id;
|
||||
@ -222,21 +183,18 @@ static inline int skl_pvtid_128(struct uuid_module *module)
|
||||
* This generates a 128 bit private unique id for a module TYPE so that
|
||||
* module instance is unique
|
||||
*/
|
||||
int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
|
||||
int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id)
|
||||
{
|
||||
struct uuid_module *module;
|
||||
uuid_le *uuid_mod;
|
||||
int pvt_id;
|
||||
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
|
||||
list_for_each_entry(module, &ctx->uuid_list, list) {
|
||||
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
|
||||
|
||||
pvt_id = skl_pvtid_128(module);
|
||||
if (pvt_id >= 0) {
|
||||
module->instance_id[pvt_id] =
|
||||
mconfig->id.instance_id;
|
||||
module->instance_id[pvt_id] = instance_id;
|
||||
|
||||
return pvt_id;
|
||||
}
|
||||
}
|
||||
@ -254,23 +212,21 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
|
||||
*
|
||||
* This frees a 128 bit private unique id previously generated
|
||||
*/
|
||||
int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
|
||||
int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id)
|
||||
{
|
||||
int i;
|
||||
uuid_le *uuid_mod;
|
||||
struct uuid_module *module;
|
||||
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
list_for_each_entry(module, &ctx->uuid_list, list) {
|
||||
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
|
||||
|
||||
if (mconfig->id.pvt_id != 0)
|
||||
i = (mconfig->id.pvt_id) / 64;
|
||||
if (*pvt_id != 0)
|
||||
i = (*pvt_id) / 64;
|
||||
else
|
||||
i = 0;
|
||||
|
||||
module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id));
|
||||
mconfig->id.pvt_id = -1;
|
||||
module->pvt_id[i] &= ~(1 << (*pvt_id));
|
||||
*pvt_id = -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -405,3 +361,83 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
|
||||
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
|
||||
struct sst_dsp_device *skl_dev)
|
||||
{
|
||||
struct skl_sst *skl;
|
||||
struct sst_dsp *sst;
|
||||
int ret;
|
||||
|
||||
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
|
||||
if (skl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
skl->dev = dev;
|
||||
skl_dev->thread_context = skl;
|
||||
INIT_LIST_HEAD(&skl->uuid_list);
|
||||
skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
dev_err(skl->dev, "%s: no device\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sst = skl->dsp;
|
||||
sst->fw_name = fw_name;
|
||||
sst->dsp_ops = dsp_ops;
|
||||
init_waitqueue_head(&skl->mod_load_wait);
|
||||
INIT_LIST_HEAD(&sst->module_list);
|
||||
ret = skl_ipc_init(dev, skl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skl->is_first_boot = true;
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
|
||||
struct firmware *stripped_fw,
|
||||
unsigned int hdr_offset, int index)
|
||||
{
|
||||
int ret;
|
||||
struct sst_dsp *dsp = skl->dsp;
|
||||
|
||||
if (linfo->fw == NULL) {
|
||||
ret = request_firmware(&linfo->fw, linfo->name,
|
||||
skl->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(skl->dev, "Request lib %s failed:%d\n",
|
||||
linfo->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (skl->is_first_boot) {
|
||||
ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
stripped_fw->data = linfo->fw->data;
|
||||
stripped_fw->size = linfo->fw->size;
|
||||
skl_dsp_strip_extended_manifest(stripped_fw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void skl_release_library(struct skl_lib_info *linfo, int lib_count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* library indices start from 1 to N. 0 represents base FW */
|
||||
for (i = 1; i < lib_count; i++) {
|
||||
if (linfo[i].fw) {
|
||||
release_firmware(linfo[i].fw);
|
||||
linfo[i].fw = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,8 @@ static int skl_transfer_firmware(struct sst_dsp *ctx,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size);
|
||||
ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size,
|
||||
true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -178,6 +179,18 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
||||
dev_err(ctx->dev, "unable to load firmware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* load libs as they are also lost on D3 */
|
||||
if (skl->lib_count > 1) {
|
||||
ret = ctx->fw_ops.load_library(ctx, skl->lib_info,
|
||||
skl->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "reload libs failed: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -203,7 +216,7 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
||||
|
||||
skl->cores.state[core_id] = SKL_DSP_RUNNING;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
|
||||
@ -323,27 +336,85 @@ static struct skl_module_table *skl_module_get_from_id(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int skl_transfer_module(struct sst_dsp *ctx,
|
||||
struct skl_load_module_info *module)
|
||||
static int skl_transfer_module(struct sst_dsp *ctx, const void *data,
|
||||
u32 size, u16 mod_id, u8 table_id, bool is_module)
|
||||
{
|
||||
int ret;
|
||||
int ret, bytes_left, curr_pos;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
skl->mod_load_complete = false;
|
||||
|
||||
ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
|
||||
module->fw->size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false);
|
||||
if (bytes_left < 0)
|
||||
return bytes_left;
|
||||
|
||||
ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
|
||||
(void *)&module->mod_id);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
|
||||
/* check is_module flag to load module or library */
|
||||
if (is_module)
|
||||
ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id);
|
||||
else
|
||||
ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to Load %s with err %d\n",
|
||||
is_module ? "module" : "lib", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* if bytes_left > 0 then wait for BDL complete interrupt and
|
||||
* copy the next chunk till bytes_left is 0. if bytes_left is
|
||||
* is zero, then wait for load module IPC reply
|
||||
*/
|
||||
while (bytes_left > 0) {
|
||||
curr_pos = size - bytes_left;
|
||||
|
||||
ret = skl_cldma_wait_interruptible(ctx);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx,
|
||||
data + curr_pos,
|
||||
bytes_left, false);
|
||||
}
|
||||
|
||||
ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete,
|
||||
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
|
||||
if (ret == 0 || !skl->mod_load_status) {
|
||||
dev_err(ctx->dev, "Module Load failed\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
ctx->cl_dev.ops.cl_stop_dma(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
kbl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
|
||||
{
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
struct firmware stripped_fw;
|
||||
int ret, i;
|
||||
|
||||
/* library indices start from 1 to N. 0 represents base FW */
|
||||
for (i = 1; i < lib_count; i++) {
|
||||
ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
|
||||
SKL_ADSP_FW_BIN_HDR_OFFSET, i);
|
||||
if (ret < 0)
|
||||
goto load_library_failed;
|
||||
ret = skl_transfer_module(ctx, stripped_fw.data,
|
||||
stripped_fw.size, 0, i, false);
|
||||
if (ret < 0)
|
||||
goto load_library_failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
load_library_failed:
|
||||
skl_release_library(linfo, lib_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
|
||||
{
|
||||
struct skl_module_table *module_entry = NULL;
|
||||
@ -365,7 +436,9 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
|
||||
}
|
||||
|
||||
if (!module_entry->usage_cnt) {
|
||||
ret = skl_transfer_module(ctx, module_entry->mod_info);
|
||||
ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data,
|
||||
module_entry->mod_info->fw->size,
|
||||
mod_id, 0, true);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to Load module\n");
|
||||
return ret;
|
||||
@ -388,6 +461,11 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
|
||||
dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* if module is used by others return, no need to unload */
|
||||
if (usage_cnt > 0)
|
||||
return 0;
|
||||
|
||||
ret = skl_ipc_unload_modules(&skl->ipc,
|
||||
SKL_NUM_MODULES, &mod_id);
|
||||
if (ret < 0) {
|
||||
@ -434,6 +512,16 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
|
||||
.unload_mod = skl_unload_module,
|
||||
};
|
||||
|
||||
static struct skl_dsp_fw_ops kbl_fw_ops = {
|
||||
.set_state_D0 = skl_set_dsp_D0,
|
||||
.set_state_D3 = skl_set_dsp_D3,
|
||||
.load_fw = skl_load_base_firmware,
|
||||
.get_fw_errcode = skl_get_errorcode,
|
||||
.load_library = kbl_load_library,
|
||||
.load_mod = skl_load_module,
|
||||
.unload_mod = skl_unload_module,
|
||||
};
|
||||
|
||||
static struct sst_ops skl_ops = {
|
||||
.irq_handler = skl_dsp_sst_interrupt,
|
||||
.write = sst_shim32_write,
|
||||
@ -455,46 +543,48 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
struct sst_dsp *sst;
|
||||
int ret;
|
||||
|
||||
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
|
||||
if (skl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
skl->dev = dev;
|
||||
skl_dev.thread_context = skl;
|
||||
INIT_LIST_HEAD(&skl->uuid_list);
|
||||
|
||||
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
dev_err(skl->dev, "%s: no device\n", __func__);
|
||||
return -ENODEV;
|
||||
ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: no device\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skl = *dsp;
|
||||
sst = skl->dsp;
|
||||
|
||||
sst->fw_name = fw_name;
|
||||
sst->addr.lpe = mmio_base;
|
||||
sst->addr.shim = mmio_base;
|
||||
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
|
||||
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
|
||||
|
||||
INIT_LIST_HEAD(&sst->module_list);
|
||||
sst->dsp_ops = dsp_ops;
|
||||
sst->fw_ops = skl_fw_ops;
|
||||
|
||||
ret = skl_ipc_init(dev, skl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skl->cores.count = 2;
|
||||
skl->is_first_boot = true;
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
|
||||
|
||||
int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp)
|
||||
{
|
||||
struct sst_dsp *sst;
|
||||
int ret;
|
||||
|
||||
ret = skl_sst_dsp_init(dev, mmio_base, irq, fw_name, dsp_ops, dsp);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: Init failed %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sst = (*dsp)->dsp;
|
||||
sst->fw_ops = kbl_fw_ops;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kbl_sst_dsp_init);
|
||||
|
||||
int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
int ret;
|
||||
@ -507,6 +597,15 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
if (ctx->lib_count > 1) {
|
||||
ret = sst->fw_ops.load_library(sst, ctx->lib_info,
|
||||
ctx->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load Library failed : %x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ctx->is_first_boot = false;
|
||||
|
||||
return 0;
|
||||
|
@ -299,8 +299,6 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
|
||||
{
|
||||
int multiplier = 1;
|
||||
struct skl_module_fmt *in_fmt, *out_fmt;
|
||||
int in_rate, out_rate;
|
||||
|
||||
|
||||
/* Since fixups is applied to pin 0 only, ibs, obs needs
|
||||
* change for pin 0 only
|
||||
@ -311,22 +309,12 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
|
||||
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
|
||||
multiplier = 5;
|
||||
|
||||
if (in_fmt->s_freq % 1000)
|
||||
in_rate = (in_fmt->s_freq / 1000) + 1;
|
||||
else
|
||||
in_rate = (in_fmt->s_freq / 1000);
|
||||
|
||||
mcfg->ibs = in_rate * (mcfg->in_fmt->channels) *
|
||||
(mcfg->in_fmt->bit_depth >> 3) *
|
||||
mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
|
||||
in_fmt->channels * (in_fmt->bit_depth >> 3) *
|
||||
multiplier;
|
||||
|
||||
if (mcfg->out_fmt->s_freq % 1000)
|
||||
out_rate = (mcfg->out_fmt->s_freq / 1000) + 1;
|
||||
else
|
||||
out_rate = (mcfg->out_fmt->s_freq / 1000);
|
||||
|
||||
mcfg->obs = out_rate * (mcfg->out_fmt->channels) *
|
||||
(mcfg->out_fmt->bit_depth >> 3) *
|
||||
mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
|
||||
out_fmt->channels * (out_fmt->bit_depth >> 3) *
|
||||
multiplier;
|
||||
}
|
||||
|
||||
@ -551,6 +539,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(w_module, &pipe->w_list, node) {
|
||||
uuid_le *uuid_mod;
|
||||
w = w_module->w;
|
||||
mconfig = w->priv;
|
||||
|
||||
@ -588,13 +577,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
|
||||
* FE/BE params
|
||||
*/
|
||||
skl_tplg_update_module_params(w, ctx);
|
||||
mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig);
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod,
|
||||
mconfig->id.instance_id);
|
||||
if (mconfig->id.pvt_id < 0)
|
||||
return ret;
|
||||
skl_tplg_set_module_init_data(w);
|
||||
ret = skl_init_module(ctx, mconfig);
|
||||
if (ret < 0) {
|
||||
skl_put_pvt_id(ctx, mconfig);
|
||||
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
|
||||
return ret;
|
||||
}
|
||||
skl_tplg_alloc_pipe_mcps(skl, mconfig);
|
||||
@ -614,7 +605,9 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
|
||||
struct skl_module_cfg *mconfig = NULL;
|
||||
|
||||
list_for_each_entry(w_module, &pipe->w_list, node) {
|
||||
uuid_le *uuid_mod;
|
||||
mconfig = w_module->w->priv;
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
|
||||
if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
|
||||
mconfig->m_state > SKL_MODULE_UNINIT) {
|
||||
@ -623,7 +616,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
}
|
||||
skl_put_pvt_id(ctx, mconfig);
|
||||
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
|
||||
}
|
||||
|
||||
/* no modules to unload in this path, so return */
|
||||
@ -645,8 +638,9 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
|
||||
struct skl_module_cfg *mconfig = w->priv;
|
||||
struct skl_pipe_module *w_module;
|
||||
struct skl_pipe *s_pipe = mconfig->pipe;
|
||||
struct skl_module_cfg *src_module = NULL, *dst_module;
|
||||
struct skl_module_cfg *src_module = NULL, *dst_module, *module;
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_module_deferred_bind *modules;
|
||||
|
||||
/* check resource available */
|
||||
if (!skl_is_pipe_mcps_avail(skl, mconfig))
|
||||
@ -687,29 +681,48 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
|
||||
src_module = dst_module;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the destination module is initialized, check for these modules
|
||||
* in deferred bind list. If found, bind them.
|
||||
*/
|
||||
list_for_each_entry(w_module, &s_pipe->w_list, node) {
|
||||
if (list_empty(&skl->bind_list))
|
||||
break;
|
||||
|
||||
list_for_each_entry(modules, &skl->bind_list, node) {
|
||||
module = w_module->w->priv;
|
||||
if (modules->dst == module)
|
||||
skl_bind_modules(ctx, modules->src,
|
||||
modules->dst);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_fill_sink_instance_id(struct skl_sst *ctx,
|
||||
struct skl_algo_data *alg_data)
|
||||
static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params,
|
||||
int size, struct skl_module_cfg *mcfg)
|
||||
{
|
||||
struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params;
|
||||
struct skl_mod_inst_map *inst;
|
||||
int i, pvt_id;
|
||||
|
||||
inst = params->map;
|
||||
if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
|
||||
struct skl_kpb_params *kpb_params =
|
||||
(struct skl_kpb_params *)params;
|
||||
struct skl_mod_inst_map *inst = kpb_params->map;
|
||||
|
||||
for (i = 0; i < params->num_modules; i++) {
|
||||
pvt_id = skl_get_pvt_instance_id_map(ctx,
|
||||
inst->mod_id, inst->inst_id);
|
||||
if (pvt_id < 0)
|
||||
return -EINVAL;
|
||||
inst->inst_id = pvt_id;
|
||||
inst++;
|
||||
for (i = 0; i < kpb_params->num_modules; i++) {
|
||||
pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id,
|
||||
inst->inst_id);
|
||||
if (pvt_id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
inst->inst_id = pvt_id;
|
||||
inst++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some modules require params to be set after the module is bound to
|
||||
* all pins connected.
|
||||
@ -726,6 +739,7 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
|
||||
struct soc_bytes_ext *sb;
|
||||
struct skl_algo_data *bc;
|
||||
struct skl_specific_cfg *sp_cfg;
|
||||
u32 *params;
|
||||
|
||||
/*
|
||||
* check all out/in pins are in bind state.
|
||||
@ -758,11 +772,18 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
|
||||
bc = (struct skl_algo_data *)sb->dobj.private;
|
||||
|
||||
if (bc->set_params == SKL_PARAM_BIND) {
|
||||
if (mconfig->m_type == SKL_MODULE_TYPE_KPB)
|
||||
skl_fill_sink_instance_id(ctx, bc);
|
||||
ret = skl_set_module_params(ctx,
|
||||
(u32 *)bc->params, bc->max,
|
||||
bc->param_id, mconfig);
|
||||
params = kzalloc(bc->max, GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(params, bc->params, bc->max);
|
||||
skl_fill_sink_instance_id(ctx, params, bc->max,
|
||||
mconfig);
|
||||
|
||||
ret = skl_set_module_params(ctx, params,
|
||||
bc->max, bc->param_id, mconfig);
|
||||
kfree(params);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@ -772,6 +793,44 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int skl_tplg_module_add_deferred_bind(struct skl *skl,
|
||||
struct skl_module_cfg *src, struct skl_module_cfg *dst)
|
||||
{
|
||||
struct skl_module_deferred_bind *m_list, *modules;
|
||||
int i;
|
||||
|
||||
/* only supported for module with static pin connection */
|
||||
for (i = 0; i < dst->max_in_queue; i++) {
|
||||
struct skl_module_pin *pin = &dst->m_in_pin[i];
|
||||
|
||||
if (pin->is_dynamic)
|
||||
continue;
|
||||
|
||||
if ((pin->id.module_id == src->id.module_id) &&
|
||||
(pin->id.instance_id == src->id.instance_id)) {
|
||||
|
||||
if (!list_empty(&skl->bind_list)) {
|
||||
list_for_each_entry(modules, &skl->bind_list, node) {
|
||||
if (modules->src == src && modules->dst == dst)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
|
||||
if (!m_list)
|
||||
return -ENOMEM;
|
||||
|
||||
m_list->src = src;
|
||||
m_list->dst = dst;
|
||||
|
||||
list_add(&m_list->node, &skl->bind_list);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
|
||||
struct skl *skl,
|
||||
struct snd_soc_dapm_widget *src_w,
|
||||
@ -806,6 +865,28 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
|
||||
sink = p->sink;
|
||||
sink_mconfig = sink->priv;
|
||||
|
||||
/*
|
||||
* Modules other than PGA leaf can be connected
|
||||
* directly or via switch to a module in another
|
||||
* pipeline. EX: reference path
|
||||
* when the path is enabled, the dst module that needs
|
||||
* to be bound may not be initialized. if the module is
|
||||
* not initialized, add these modules in the deferred
|
||||
* bind list and when the dst module is initialised,
|
||||
* bind this module to the dst_module in deferred list.
|
||||
*/
|
||||
if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
|
||||
&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
|
||||
|
||||
ret = skl_tplg_module_add_deferred_bind(skl,
|
||||
src_mconfig, sink_mconfig);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
|
||||
sink_mconfig->m_state == SKL_MODULE_UNINIT)
|
||||
continue;
|
||||
@ -985,15 +1066,6 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
|
||||
if (!src_mconfig)
|
||||
continue;
|
||||
/*
|
||||
* If path_found == 1, that means pmd for source
|
||||
* pipe has not occurred, source is connected to
|
||||
* some other sink. so its responsibility of sink
|
||||
* to unbind itself from source.
|
||||
*/
|
||||
ret = skl_stop_pipe(ctx, src_mconfig->pipe);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = skl_unbind_modules(ctx,
|
||||
src_mconfig, sink_mconfig);
|
||||
@ -1019,6 +1091,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
struct skl_module_cfg *src_module = NULL, *dst_module;
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_pipe *s_pipe = mconfig->pipe;
|
||||
struct skl_module_deferred_bind *modules, *tmp;
|
||||
|
||||
if (s_pipe->state == SKL_PIPE_INVALID)
|
||||
return -EINVAL;
|
||||
@ -1026,6 +1099,35 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
skl_tplg_free_pipe_mcps(skl, mconfig);
|
||||
skl_tplg_free_pipe_mem(skl, mconfig);
|
||||
|
||||
list_for_each_entry(w_module, &s_pipe->w_list, node) {
|
||||
if (list_empty(&skl->bind_list))
|
||||
break;
|
||||
|
||||
src_module = w_module->w->priv;
|
||||
|
||||
list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
|
||||
/*
|
||||
* When the destination module is deleted, Unbind the
|
||||
* modules from deferred bind list.
|
||||
*/
|
||||
if (modules->dst == src_module) {
|
||||
skl_unbind_modules(ctx, modules->src,
|
||||
modules->dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the source module is deleted, remove this entry
|
||||
* from the deferred bind list.
|
||||
*/
|
||||
if (modules->src == src_module) {
|
||||
list_del(&modules->node);
|
||||
modules->src = NULL;
|
||||
modules->dst = NULL;
|
||||
kfree(modules);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(w_module, &s_pipe->w_list, node) {
|
||||
dst_module = w_module->w->priv;
|
||||
|
||||
@ -1042,6 +1144,11 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
|
||||
skl_delete_pipe(ctx, mconfig->pipe);
|
||||
|
||||
list_for_each_entry(w_module, &s_pipe->w_list, node) {
|
||||
src_module = w_module->w->priv;
|
||||
src_module->m_state = SKL_MODULE_UNINIT;
|
||||
}
|
||||
|
||||
return skl_tplg_unload_pipe_modules(ctx, s_pipe);
|
||||
}
|
||||
|
||||
@ -1082,36 +1189,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* In modelling, we assume there will be ONLY one mixer in a pipeline. If
|
||||
* mixer is not required then it is treated as static mixer aka vmixer with
|
||||
* a hard path to source module
|
||||
* So we don't need to check if source is started or not as hard path puts
|
||||
* dependency on each other
|
||||
*/
|
||||
static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||
struct skl *skl = get_skl_ctx(dapm->dev);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
|
||||
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
|
||||
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In modelling, we assume there will be ONLY one mixer in a pipeline. If a
|
||||
* second one is required that is created as another pipe entity.
|
||||
@ -1252,10 +1329,12 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
|
||||
case SKL_DEVICE_HDALINK:
|
||||
pipe->p_params->link_dma_id = params->link_dma_id;
|
||||
pipe->p_params->link_index = params->link_index;
|
||||
pipe->p_params->link_bps = params->link_bps;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_HDAHOST:
|
||||
pipe->p_params->host_dma_id = params->host_dma_id;
|
||||
pipe->p_params->host_bps = params->host_bps;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1578,7 +1657,7 @@ int skl_tplg_be_update_params(struct snd_soc_dai *dai,
|
||||
|
||||
static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
|
||||
{SKL_MIXER_EVENT, skl_tplg_mixer_event},
|
||||
{SKL_VMIXER_EVENT, skl_tplg_vmixer_event},
|
||||
{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
|
||||
{SKL_PGA_EVENT, skl_tplg_pga_event},
|
||||
};
|
||||
|
||||
@ -1632,7 +1711,7 @@ static int skl_tplg_add_pipe(struct device *dev,
|
||||
list_for_each_entry(ppl, &skl->ppl_list, node) {
|
||||
if (ppl->pipe->ppl_id == tkn_elem->value) {
|
||||
mconfig->pipe = ppl->pipe;
|
||||
return EEXIST;
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1924,11 +2003,13 @@ static int skl_tplg_get_token(struct device *dev,
|
||||
ret = skl_tplg_add_pipe(dev,
|
||||
mconfig, skl, tkn_elem);
|
||||
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
if (ret == -EEXIST) {
|
||||
is_pipe_exists = 1;
|
||||
break;
|
||||
}
|
||||
return is_pipe_exists;
|
||||
|
||||
if (ret == EEXIST)
|
||||
is_pipe_exists = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -257,6 +257,8 @@ struct skl_pipe_params {
|
||||
snd_pcm_format_t format;
|
||||
int link_index;
|
||||
int stream;
|
||||
unsigned int host_bps;
|
||||
unsigned int link_bps;
|
||||
};
|
||||
|
||||
struct skl_pipe {
|
||||
@ -334,17 +336,10 @@ struct skl_pipeline {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
#define SKL_LIB_NAME_LENGTH 128
|
||||
#define SKL_MAX_LIB 16
|
||||
|
||||
struct skl_lib_info {
|
||||
char name[SKL_LIB_NAME_LENGTH];
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
struct skl_manifest {
|
||||
u32 lib_count;
|
||||
struct skl_lib_info lib[SKL_MAX_LIB];
|
||||
struct skl_module_deferred_bind {
|
||||
struct skl_module_cfg *src;
|
||||
struct skl_module_cfg *dst;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static inline struct skl *get_skl_ctx(struct device *dev)
|
||||
|
@ -512,7 +512,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
|
||||
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
|
||||
unsigned int res;
|
||||
unsigned int res = -1;
|
||||
|
||||
mutex_lock(&bus->cmd_mutex);
|
||||
snd_hdac_bus_send_cmd(bus, cmd);
|
||||
|
@ -77,6 +77,7 @@ struct skl {
|
||||
|
||||
struct skl_dsp_resource resource;
|
||||
struct list_head ppl_list;
|
||||
struct list_head bind_list;
|
||||
|
||||
const char *fw_name;
|
||||
char tplg_name[64];
|
||||
|
@ -1913,6 +1913,7 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
||||
EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
|
||||
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
/* Trim special characters, and replace '-' with '_' since '-' is used to
|
||||
* separate different DMI fields in the card long name. Only number and
|
||||
* alphabet characters and a few separator characters are kept.
|
||||
@ -2044,6 +2045,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
|
||||
#endif /* CONFIG_DMI */
|
||||
|
||||
static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
{
|
||||
@ -2185,6 +2187,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
|
||||
card->num_of_dapm_routes);
|
||||
|
||||
/* try to set some sane longname if DMI is available */
|
||||
snd_soc_set_dmi_name(card, NULL);
|
||||
|
||||
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
|
||||
"%s", card->name);
|
||||
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
|
||||
|
Loading…
Reference in New Issue
Block a user