Commit 0c2964cb authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/intel' into asoc-next

parents d872f046 081dc8ab
...@@ -497,7 +497,15 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream); ...@@ -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, int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
unsigned int dai_fmt); unsigned int dai_fmt);
#ifdef CONFIG_DMI
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour); 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 */ /* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); 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) ...@@ -268,7 +268,7 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
unsigned int offset; unsigned int offset;
unsigned int counter = 0; unsigned int counter = 0;
offset = snd_hdac_chip_readl(bus, LLCH); offset = snd_hdac_chip_readw(bus, LLCH);
/* Lets walk the linked capabilities list */ /* Lets walk the linked capabilities list */
do { do {
......
...@@ -469,7 +469,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, ...@@ -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), format = snd_hdac_calc_stream_format(params_rate(hparams),
params_channels(hparams), params_format(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); pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
if (!pcm) if (!pcm)
...@@ -1419,8 +1419,8 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac, ...@@ -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.rate_min = rate_min;
hdmi_dais[i].playback.channels_min = 2; hdmi_dais[i].playback.channels_min = 2;
hdmi_dais[i].playback.channels_max = 2; hdmi_dais[i].playback.channels_max = 2;
hdmi_dais[i].playback.sig_bits = bps;
hdmi_dais[i].ops = &hdmi_dai_ops; hdmi_dais[i].ops = &hdmi_dai_ops;
i++; i++;
} }
......
...@@ -2835,6 +2835,27 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { ...@@ -2835,6 +2835,27 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"), 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 ...@@ -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. platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
If unsure select "N". 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 config SND_SOC_INTEL_SKYLAKE
tristate tristate
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
......
...@@ -420,7 +420,21 @@ static const struct dmi_system_id byt_table[] = { ...@@ -420,7 +420,21 @@ static const struct dmi_system_id byt_table[] = {
.callback = byt_thinkpad10_quirk_cb, .callback = byt_thinkpad10_quirk_cb,
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 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[] = { ...@@ -480,12 +494,23 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
&byt_rvp_platform_data }, &byt_rvp_platform_data },
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
&byt_rvp_platform_data }, &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 */ /* some Baytrail platforms rely on RT5645, use CHT machine driver */
{"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
&byt_rvp_platform_data }, &byt_rvp_platform_data },
{"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
&byt_rvp_platform_data }, &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[] = { ...@@ -504,6 +529,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }, &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 */ /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
&chv_platform_data }, &chv_platform_data },
...@@ -512,6 +541,14 @@ static struct sst_acpi_mach sst_acpi_chv[] = { ...@@ -512,6 +541,14 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
/* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL,
&chv_platform_data }, &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, ...@@ -236,7 +236,9 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
retval = init->result; retval = init->result;
goto ret; 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.type, init->fw_version.major,
init->fw_version.minor, init->fw_version.build); init->fw_version.minor, init->fw_version.build);
dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", 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 ...@@ -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-rt5672-objs := cht_bsw_rt5672.o
snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.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-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-soc-skl_rt286-objs := skl_rt286.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.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 ...@@ -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_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_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_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_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_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.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) ...@@ -193,13 +193,12 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
RT5677_CLK_SEL_I2S1_ASRC); RT5677_CLK_SEL_I2S1_ASRC);
/* Request rt5677 GPIO for headphone amp control */ /* Request rt5677 GPIO for headphone amp control */
bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev, bdw_rt5677->gpio_hp_en = devm_gpiod_get(codec->dev, "headphone-enable",
"headphone-enable", 0, 0); GPIOD_OUT_LOW);
if (IS_ERR(bdw_rt5677->gpio_hp_en)) { if (IS_ERR(bdw_rt5677->gpio_hp_en)) {
dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n"); dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n");
return PTR_ERR(bdw_rt5677->gpio_hp_en); return PTR_ERR(bdw_rt5677->gpio_hp_en);
} }
gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0);
/* Create and initialize headphone jack */ /* Create and initialize headphone jack */
if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack",
......
...@@ -269,9 +269,6 @@ static struct snd_soc_card broadwell_rt286 = { ...@@ -269,9 +269,6 @@ static struct snd_soc_card broadwell_rt286 = {
static int broadwell_audio_probe(struct platform_device *pdev) static int broadwell_audio_probe(struct platform_device *pdev)
{ {
broadwell_rt286.dev = &pdev->dev; broadwell_rt286.dev = &pdev->dev;
snd_soc_set_dmi_name(&broadwell_rt286, NULL);
return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
} }
......
...@@ -55,6 +55,54 @@ enum { ...@@ -55,6 +55,54 @@ enum {
BXT_DPCM_AUDIO_HDMI3_PB, 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[] = { static const struct snd_kcontrol_new broxton_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
...@@ -69,6 +117,8 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { ...@@ -69,6 +117,8 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = {
SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL),
SND_SOC_DAPM_SPK("HDMI3", 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[] = { static const struct snd_soc_dapm_route broxton_map[] = {
...@@ -109,6 +159,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { ...@@ -109,6 +159,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
/* DMIC */ /* DMIC */
{"dmic01_hifi", NULL, "DMIC01 Rx"}, {"dmic01_hifi", NULL, "DMIC01 Rx"},
{"DMIC01 Rx", NULL, "DMIC AIF"}, {"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, 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 = { ...@@ -243,49 +296,6 @@ static const struct snd_soc_ops broxton_da7219_fe_ops = {
.startup = bxt_fe_startup, .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, static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -467,7 +477,6 @@ static struct snd_soc_dai_link broxton_dais[] = { ...@@ -467,7 +477,6 @@ static struct snd_soc_dai_link broxton_dais[] = {
SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1, .ignore_pmdown_time = 1,
.be_hw_params_fixup = broxton_ssp_fixup, .be_hw_params_fixup = broxton_ssp_fixup,
.ops = &broxton_da7219_ops,
.dpcm_playback = 1, .dpcm_playback = 1,
.dpcm_capture = 1, .dpcm_capture = 1,
}, },
......
...@@ -274,12 +274,15 @@ static int bxt_fe_startup(struct snd_pcm_substream *substream) ...@@ -274,12 +274,15 @@ static int bxt_fe_startup(struct snd_pcm_substream *substream)
* on this platform for PCM device we support: * on this platform for PCM device we support:
* 48Khz * 48Khz
* stereo * stereo
* 16-bit audio
*/ */
runtime->hw.channels_max = 2; runtime->hw.channels_max = 2;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_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, snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
......
/*
* 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");
/*
* 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 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -56,35 +57,88 @@ enum { ...@@ -56,35 +57,88 @@ enum {
struct byt_rt5640_private { struct byt_rt5640_private {
struct clk *mclk; struct clk *mclk;
}; };
static bool is_bytcr;
static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; 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) static void log_quirks(struct device *dev)
{ {
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP) int map;
dev_info(dev, "quirk DMIC1_MAP enabled"); bool has_dmic = false;
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP) bool has_mclk = false;
dev_info(dev, "quirk DMIC2_MAP enabled"); bool has_ssp0 = false;
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP) bool has_ssp0_aif1 = false;
dev_info(dev, "quirk IN1_MAP enabled"); bool has_ssp0_aif2 = false;
if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP) bool has_ssp2_aif2 = false;
dev_info(dev, "quirk IN3_MAP enabled");
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) map = BYT_RT5640_MAP(byt_rt5640_quirk);
dev_info(dev, "quirk DMIC enabled"); 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) if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
dev_info(dev, "quirk MONO_SPEAKER enabled"); dev_info(dev, "quirk MONO_SPEAKER enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
dev_info(dev, "quirk DIFF_MIC enabled"); if (!has_dmic)
if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) dev_info(dev, "quirk DIFF_MIC enabled\n");
dev_info(dev, "quirk SSP2_AIF2 enabled"); else
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\n");
dev_info(dev, "quirk SSP0_AIF1 enabled"); }
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
dev_info(dev, "quirk SSP0_AIF2 enabled"); dev_info(dev, "quirk SSP0_AIF1 enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) has_ssp0 = true;
dev_info(dev, "quirk MCLK_EN enabled"); has_ssp0_aif1 = true;
if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) }
dev_info(dev, "quirk MCLK_25MHZ enabled"); 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, ...@@ -128,7 +182,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
ret = clk_prepare_enable(priv->mclk); ret = clk_prepare_enable(priv->mclk);
if (ret < 0) { if (ret < 0) {
dev_err(card->dev, dev_err(card->dev,
"could not configure MCLK state"); "could not configure MCLK state\n");
return ret; return ret;
} }
} }
...@@ -710,8 +764,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) ...@@ -710,8 +764,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
int i; int i;
int dai_index; int dai_index;
struct byt_rt5640_private *priv; struct byt_rt5640_private *priv;
bool is_bytcr = false;
is_bytcr = false;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
...@@ -806,6 +860,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) ...@@ -806,6 +860,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
/* check quirks before creating card */ /* check quirks before creating card */
dmi_check_system(byt_rt5640_quirk_table); 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); log_quirks(&pdev->dev);
if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
......
...@@ -2000,10 +2000,8 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, ...@@ -2000,10 +2000,8 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw,
u32 param_size, char *param) u32 param_size, char *param)
{ {
int ret; int ret;
unsigned char *data = NULL;
u32 header = 0; u32 header = 0;
u32 payload_size = 0, transfer_parameter_size = 0; u32 payload_size = 0, transfer_parameter_size = 0;
dma_addr_t dma_addr = 0;
struct sst_hsw_transfer_parameter *parameter; struct sst_hsw_transfer_parameter *parameter;
struct device *dev = hsw->dev; struct device *dev = hsw->dev;
...@@ -2047,10 +2045,6 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, ...@@ -2047,10 +2045,6 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw,
kfree(parameter); kfree(parameter);
if (data)
dma_free_coherent(hsw->dsp->dma_dev,
param_size, (void *)data, dma_addr);
return ret; return ret;
} }
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
#define BXT_BASEFW_TIMEOUT 3000 #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_IPC_PURGE_FW 0x01004000
#define BXT_ROM_INIT 0x5 #define BXT_ROM_INIT 0x5
...@@ -45,6 +46,8 @@ ...@@ -45,6 +46,8 @@
/* Delay before scheduling D0i3 entry */ /* Delay before scheduling D0i3 entry */
#define BXT_D0I3_DELAY 5000 #define BXT_D0I3_DELAY 5000
#define BXT_FW_ROM_INIT_RETRY 3
static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
{ {
return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); 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) ...@@ -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 snd_dma_buffer dmab;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
const struct firmware *fw = NULL;
struct firmware stripped_fw; struct firmware stripped_fw;
int ret = 0, i, dma_id, stream_tag; int ret = 0, i, dma_id, stream_tag;
/* library indices start from 1 to N. 0 represents base FW */ /* library indices start from 1 to N. 0 represents base FW */
for (i = 1; i < lib_count; i++) { for (i = 1; i < lib_count; i++) {
ret = request_firmware(&fw, linfo[i].name, ctx->dev); ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
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,
BXT_ADSP_FW_BIN_HDR_OFFSET, i); BXT_ADSP_FW_BIN_HDR_OFFSET, i);
if (ret < 0) if (ret < 0)
goto load_library_failed; goto load_library_failed;
}
stripped_fw.data = fw->data;
stripped_fw.size = fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40,
stripped_fw.size, &dmab); stripped_fw.size, &dmab);
...@@ -92,21 +81,19 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) ...@@ -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); memcpy(dmab.area, stripped_fw.data, stripped_fw.size);
ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); 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) if (ret < 0)
dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
linfo[i].name, ret); linfo[i].name, ret);
ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
release_firmware(fw);
fw = NULL;
} }
return ret; return ret;
load_library_failed: load_library_failed:
release_firmware(fw); skl_release_library(linfo, lib_count);
return ret; return ret;
} }
...@@ -156,7 +143,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -156,7 +143,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE,
BXT_INIT_TIMEOUT, "HIPCIE Done"); BXT_INIT_TIMEOUT, "HIPCIE Done");
if (ret < 0) { 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; goto base_fw_load_failed;
} }
...@@ -173,7 +160,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -173,7 +160,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
/* Step 7: Wait for ROM init */ /* Step 7: Wait for ROM init */
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, 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) { if (ret < 0) {
dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
goto base_fw_load_failed; goto base_fw_load_failed;
...@@ -206,18 +193,16 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) ...@@ -206,18 +193,16 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
{ {
struct firmware stripped_fw; struct firmware stripped_fw;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
int ret; int ret, i;
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); if (ctx->fw == NULL) {
if (ret < 0) { ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
dev_err(ctx->dev, "Request firmware failed %d\n", ret); if (ret < 0) {
goto sst_load_base_firmware_failed; 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 */ /* prase uuids on first boot */
if (skl->is_first_boot) { if (skl->is_first_boot) {
ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); 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) ...@@ -229,18 +214,20 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
stripped_fw.size = ctx->fw->size; stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw); 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 */ for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) {
if (ret < 0) {
ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
if (ret < 0) { if (ret == 0)
dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", 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_ERROR_CODE),
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
goto sst_load_base_firmware_failed; goto sst_load_base_firmware_failed;
}
} }
ret = sst_transfer_fw_host_dma(ctx); ret = sst_transfer_fw_host_dma(ctx);
...@@ -265,8 +252,11 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) ...@@ -265,8 +252,11 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
} }
} }
return ret;
sst_load_base_firmware_failed: sst_load_base_firmware_failed:
release_firmware(ctx->fw); release_firmware(ctx->fw);
ctx->fw = NULL;
return ret; return ret;
} }
...@@ -428,6 +418,7 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) ...@@ -428,6 +418,7 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
return ret; return ret;
} }
} }
skl->cores.state[core_id] = SKL_DSP_RUNNING;
return ret; return ret;
} }
...@@ -514,11 +505,22 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) ...@@ -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, ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
BXT_BASE_FW_MODULE_ID, &dx); BXT_BASE_FW_MODULE_ID, &dx);
if (ret < 0) if (ret < 0) {
dev_err(ctx->dev, dev_err(ctx->dev,
"Failed to set DSP to D3:core id = %d;Continue reset\n", "Failed to set DSP to D3:core id = %d;Continue reset\n",
core_id); 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); ret = skl_dsp_disable_core(ctx, core_mask);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Failed to disable core %d\n", ret); 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, ...@@ -560,23 +562,14 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
struct sst_dsp *sst; struct sst_dsp *sst;
int ret; int ret;
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
if (skl == NULL) if (ret < 0) {
return -ENOMEM; dev_err(dev, "%s: no device\n", __func__);
return ret;
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;
} }
skl = *dsp;
sst = skl->dsp; sst = skl->dsp;
sst->fw_name = fw_name;
sst->dsp_ops = dsp_ops;
sst->fw_ops = bxt_fw_ops; sst->fw_ops = bxt_fw_ops;
sst->addr.lpe = mmio_base; sst->addr.lpe = mmio_base;
sst->addr.shim = 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, ...@@ -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), 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); 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 */ /* set the D0i3 check */
skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
skl->cores.count = 2; skl->cores.count = 2;
skl->boot_complete = false; skl->boot_complete = false;
init_waitqueue_head(&skl->boot_wait); init_waitqueue_head(&skl->boot_wait);
skl->is_first_boot = true;
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
skl->d0i3.state = SKL_DSP_D0I3_NONE; skl->d0i3.state = SKL_DSP_D0I3_NONE;
if (dsp)
*dsp = skl;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
...@@ -635,6 +619,10 @@ EXPORT_SYMBOL_GPL(bxt_sst_init_fw); ...@@ -635,6 +619,10 @@ EXPORT_SYMBOL_GPL(bxt_sst_init_fw);
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) 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_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc); skl_ipc_free(&ctx->ipc);
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); 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) ...@@ -58,7 +58,7 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
#define NOTIFICATION_MASK 0xf #define NOTIFICATION_MASK 0xf
/* disable notfication for underruns/overruns from firmware module */ /* 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 notification_mask mask;
struct skl_ipc_large_config_msg msg = {0}; struct skl_ipc_large_config_msg msg = {0};
...@@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = { ...@@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
{ {
.id = 0x9d71, .id = 0x9d71,
.loader_ops = skl_get_loader_ops, .loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init, .init = kbl_sst_dsp_init,
.init_fw = skl_sst_init_fw, .init_fw = skl_sst_init_fw,
.cleanup = skl_sst_dsp_cleanup .cleanup = skl_sst_dsp_cleanup
}, },
...@@ -274,6 +274,7 @@ int skl_init_dsp(struct skl *skl) ...@@ -274,6 +274,7 @@ int skl_init_dsp(struct skl *skl)
if (ret < 0) if (ret < 0)
return ret; return ret;
skl->skl_sst->dsp_ops = ops;
dev_dbg(bus->dev, "dsp registration status=%d\n", ret); dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
return ret; return ret;
...@@ -284,16 +285,11 @@ int skl_free_dsp(struct skl *skl) ...@@ -284,16 +285,11 @@ int skl_free_dsp(struct skl *skl)
struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_ext_bus *ebus = &skl->ebus;
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
struct skl_sst *ctx = skl->skl_sst; struct skl_sst *ctx = skl->skl_sst;
const struct skl_dsp_ops *ops;
/* disable ppcap interrupt */ /* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
ops = skl_get_dsp_ops(skl->pci->device); ctx->dsp_ops->cleanup(bus->dev, ctx);
if (!ops)
return -EIO;
ops->cleanup(bus->dev, ctx);
if (ctx->dsp->addr.lpe) if (ctx->dsp->addr.lpe)
iounmap(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, ...@@ -866,7 +862,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
} }
if (!found) if (!found)
mcfg->m_state = SKL_MODULE_UNINIT; mcfg->m_state = SKL_MODULE_INIT_DONE;
return; return;
} }
...@@ -1098,7 +1094,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ...@@ -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); dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
/* If pipe is started, do stop the pipe in FW. */ /* 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); ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Failed to stop pipeline\n"); dev_err(ctx->dev, "Failed to stop pipeline\n");
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; 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) struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
{ {
acpi_handle handle; acpi_handle handle;
...@@ -33,8 +31,9 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) ...@@ -33,8 +31,9 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
struct nhlt_resource_desc *nhlt_ptr = NULL; struct nhlt_resource_desc *nhlt_ptr = NULL;
struct nhlt_acpi_table *nhlt_table = NULL; struct nhlt_acpi_table *nhlt_table = NULL;
if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { handle = ACPI_HANDLE(dev);
dev_err(dev, "Requested NHLT device not found\n"); if (!handle) {
dev_err(dev, "Didn't find ACPI_HANDLE\n");
return NULL; return NULL;
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include "skl.h" #include "skl.h"
...@@ -155,7 +156,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) ...@@ -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); snd_hdac_ext_stream_decouple(ebus, stream, true);
format_val = snd_hdac_calc_stream_format(params->s_freq, 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", dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format); 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) ...@@ -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); stream = stream_to_hdac_ext_stream(hstream);
snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_stream_decouple(ebus, stream, true);
format_val = snd_hdac_calc_stream_format(params->s_freq, format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
params->ch, params->format, 24, 0); params->format, params->link_bps, 0);
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format); format_val, params->s_freq, params->ch, params->format);
...@@ -262,23 +263,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, ...@@ -262,23 +263,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
return 0; 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, static int skl_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -326,6 +310,11 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -326,6 +310,11 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
p_params.host_dma_id = dma_id; p_params.host_dma_id = dma_id;
p_params.stream = substream->stream; p_params.stream = substream->stream;
p_params.format = params_format(params); 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); m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
if (m_cfg) if (m_cfg)
...@@ -564,6 +553,11 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, ...@@ -564,6 +553,11 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
p_params.link_index = link->index; p_params.link_index = link->index;
p_params.format = params_format(params); 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); return skl_tplg_be_update_params(dai, &p_params);
} }
...@@ -649,7 +643,6 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { ...@@ -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 = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params, .hw_params = skl_be_hw_params,
.prepare = skl_be_prepare,
}; };
static struct snd_soc_dai_ops skl_link_dai_ops = { static struct snd_soc_dai_ops skl_link_dai_ops = {
...@@ -670,6 +663,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -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, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 32,
}, },
.capture = { .capture = {
.stream_name = "System Capture", .stream_name = "System Capture",
...@@ -677,6 +671,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -677,6 +671,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.channels_max = HDA_STEREO, .channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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[] = { ...@@ -688,6 +683,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.channels_max = HDA_QUAD, .channels_max = HDA_QUAD,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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[] = { ...@@ -699,6 +695,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.channels_max = HDA_STEREO, .channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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[] = { ...@@ -710,6 +707,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.channels_max = HDA_STEREO, .channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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[] = { ...@@ -721,6 +719,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.channels_max = HDA_QUAD, .channels_max = HDA_QUAD,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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[] = { ...@@ -736,6 +735,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
SNDRV_PCM_RATE_192000, SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE, SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 32,
}, },
}, },
{ {
...@@ -751,6 +751,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -751,6 +751,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
SNDRV_PCM_RATE_192000, SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE, SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 32,
}, },
}, },
{ {
...@@ -766,6 +767,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -766,6 +767,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
SNDRV_PCM_RATE_192000, SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE, SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 32,
}, },
}, },
...@@ -949,14 +951,12 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -949,14 +951,12 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
static int skl_platform_open(struct snd_pcm_substream *substream) 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_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai_link *dai_link = rtd->dai_link;
dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__,
dai_link->cpu_dai_name); dai_link->cpu_dai_name);
runtime = substream->runtime;
snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw);
return 0; return 0;
...@@ -1062,13 +1062,31 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer ...@@ -1062,13 +1062,31 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
* HAD space reflects the actual data that is transferred. * HAD space reflects the actual data that is transferred.
* Use the position buffer for capture, as DPIB write gets * Use the position buffer for capture, as DPIB write gets
* completed earlier than the actual data written to the DDR. * 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 + pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL * (AZX_REG_VS_SDXDPIB_XINTERVAL *
hdac_stream(hstream)->index)); 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)); pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
}
if (pos >= hdac_stream(hstream)->bufsize) if (pos >= hdac_stream(hstream)->bufsize)
pos = 0; pos = 0;
...@@ -1165,7 +1183,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -1165,7 +1183,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
snd_dma_pci_data(skl->pci), snd_dma_pci_data(skl->pci),
size, MAX_PREALLOC_SIZE); size, MAX_PREALLOC_SIZE);
if (retval) { if (retval) {
dev_err(dai->dev, "dma buffer allocationf fail\n"); dev_err(dai->dev, "dma buffer allocation fail\n");
return retval; return retval;
} }
} }
...@@ -1173,29 +1191,52 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -1173,29 +1191,52 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
return retval; 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) static int skl_populate_modules(struct skl *skl)
{ {
struct skl_pipeline *p; struct skl_pipeline *p;
struct skl_pipe_module *m; struct skl_pipe_module *m;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
struct skl_module_cfg *mconfig; struct skl_module_cfg *mconfig;
int ret; int ret = 0;
list_for_each_entry(p, &skl->ppl_list, node) { list_for_each_entry(p, &skl->ppl_list, node) {
list_for_each_entry(m, &p->pipe->w_list, node) { list_for_each_entry(m, &p->pipe->w_list, node) {
w = m->w; w = m->w;
mconfig = w->priv; mconfig = w->priv;
ret = snd_skl_get_module_info(skl->skl_sst, mconfig); ret = skl_get_module_info(skl, mconfig);
if (ret < 0) { if (ret < 0) {
dev_err(skl->skl_sst->dev, dev_err(skl->skl_sst->dev,
"query module info failed:%d\n", ret); "query module info failed\n");
goto err; return ret;
} }
} }
} }
err:
return ret; return ret;
} }
...@@ -1232,6 +1273,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) ...@@ -1232,6 +1273,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
} }
skl_populate_modules(skl); skl_populate_modules(skl);
skl->skl_sst->update_d0i3c = skl_update_d0i3c; 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_mark_last_busy(platform->dev);
pm_runtime_put_autosuspend(platform->dev); pm_runtime_put_autosuspend(platform->dev);
...@@ -1256,6 +1298,7 @@ int skl_platform_register(struct device *dev) ...@@ -1256,6 +1298,7 @@ int skl_platform_register(struct device *dev)
struct skl *skl = ebus_to_skl(ebus); struct skl *skl = ebus_to_skl(ebus);
INIT_LIST_HEAD(&skl->ppl_list); INIT_LIST_HEAD(&skl->ppl_list);
INIT_LIST_HEAD(&skl->bind_list);
ret = snd_soc_register_platform(dev, &skl_platform_drv); ret = snd_soc_register_platform(dev, &skl_platform_drv);
if (ret) { if (ret) {
...@@ -1276,6 +1319,17 @@ int skl_platform_register(struct device *dev) ...@@ -1276,6 +1319,17 @@ int skl_platform_register(struct device *dev)
int skl_platform_unregister(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_component(dev);
snd_soc_unregister_platform(dev); snd_soc_unregister_platform(dev);
return 0; return 0;
......
...@@ -164,7 +164,7 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx) ...@@ -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); 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; int ret = 0;
...@@ -243,9 +243,14 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, ...@@ -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 * 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 * fill the ring buffer. Caller takes care of polling the required status
* register to identify the transfer 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 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; int ret = 0;
bool start = true; bool start = true;
...@@ -272,13 +277,14 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) ...@@ -272,13 +277,14 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
size = ctx->cl_dev.bufsize; size = ctx->cl_dev.bufsize;
skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); skl_cldma_fill_buffer(ctx, size, curr_pos, true, start);
start = false; if (wait) {
ret = skl_cldma_wait_interruptible(ctx); start = false;
if (ret < 0) { ret = skl_cldma_wait_interruptible(ctx);
skl_cldma_stop(ctx); if (ret < 0) {
return ret; skl_cldma_stop(ctx);
return ret;
}
} }
} else { } else {
skl_cldma_int_disable(ctx); skl_cldma_int_disable(ctx);
...@@ -298,9 +304,11 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) ...@@ -298,9 +304,11 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
} }
bytes_left -= size; bytes_left -= size;
curr_pos = curr_pos + 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) void skl_cldma_process_intr(struct sst_dsp *ctx)
......
...@@ -213,7 +213,7 @@ struct skl_cl_dev_ops { ...@@ -213,7 +213,7 @@ struct skl_cl_dev_ops {
void (*cl_trigger)(struct sst_dsp *ctx, bool enable); void (*cl_trigger)(struct sst_dsp *ctx, bool enable);
void (*cl_cleanup_controller)(struct sst_dsp *ctx); void (*cl_cleanup_controller)(struct sst_dsp *ctx);
int (*cl_copy_to_dmabuf)(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); 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) ...@@ -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); ret = ctx->fw_ops.set_state_D0(ctx, core_id);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "unable to get core%d\n", core_id); dev_err(ctx->dev, "unable to get core%d\n", core_id);
return ret; goto out;
} }
} }
skl->cores.usage_count[core_id]++; skl->cores.usage_count[core_id]++;
out:
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id], core_id, skl->cores.state[core_id],
skl->cores.usage_count[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) ...@@ -379,7 +380,8 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id)
return -EINVAL; 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); ret = ctx->fw_ops.set_state_D3(ctx, core_id);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "unable to put core %d: %d\n", dev_err(ctx->dev, "unable to put core %d: %d\n",
......
...@@ -17,13 +17,15 @@ ...@@ -17,13 +17,15 @@
#define __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/uuid.h>
#include <linux/firmware.h>
#include <sound/memalloc.h> #include <sound/memalloc.h>
#include "skl-sst-cldma.h" #include "skl-sst-cldma.h"
#include "skl-topology.h"
struct sst_dsp; struct sst_dsp;
struct skl_sst; struct skl_sst;
struct sst_dsp_device; struct sst_dsp_device;
struct skl_lib_info;
/* Intel HD Audio General DSP Registers */ /* Intel HD Audio General DSP Registers */
#define SKL_ADSP_GEN_BASE 0x0 #define SKL_ADSP_GEN_BASE 0x0
...@@ -144,7 +146,7 @@ struct skl_dsp_fw_ops { ...@@ -144,7 +146,7 @@ struct skl_dsp_fw_ops {
int (*load_fw)(struct sst_dsp *ctx); int (*load_fw)(struct sst_dsp *ctx);
/* FW module parser/loader */ /* FW module parser/loader */
int (*load_library)(struct sst_dsp *ctx, 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 (*parse_fw)(struct sst_dsp *ctx);
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
int (*set_state_D3)(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 { ...@@ -172,6 +174,19 @@ struct skl_dsp_loader_ops {
int stream_tag); 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 { struct skl_load_module_info {
u16 mod_id; u16 mod_id;
const struct firmware *fw; const struct firmware *fw;
...@@ -186,6 +201,7 @@ struct skl_module_table { ...@@ -186,6 +201,7 @@ struct skl_module_table {
void skl_cldma_process_intr(struct sst_dsp *ctx); void skl_cldma_process_intr(struct sst_dsp *ctx);
void skl_cldma_int_disable(struct sst_dsp *ctx); void skl_cldma_int_disable(struct sst_dsp *ctx);
int skl_cldma_prepare(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); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
...@@ -214,6 +230,9 @@ int skl_dsp_boot(struct sst_dsp *ctx); ...@@ -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, 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, const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp); 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, 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, const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp); struct skl_sst **dsp);
...@@ -222,17 +241,22 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); ...@@ -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 skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
void bxt_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, int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
unsigned int offset, int index); unsigned int offset, int index);
int skl_get_pvt_id(struct skl_sst *ctx, int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id);
struct skl_module_cfg *mconfig); int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id);
int skl_put_pvt_id(struct skl_sst *ctx,
struct skl_module_cfg *mconfig);
int skl_get_pvt_instance_id_map(struct skl_sst *ctx, int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
int module_id, int instance_id); int module_id, int instance_id);
void skl_freeup_uuid_list(struct skl_sst *ctx); void skl_freeup_uuid_list(struct skl_sst *ctx);
int skl_dsp_strip_extended_manifest(struct firmware *fw); 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__*/ #endif /*__SKL_SST_DSP_H__*/
...@@ -34,6 +34,11 @@ ...@@ -34,6 +34,11 @@
#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) #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_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_TIMEOUT_MSECS 3000
#define IPC_EMPTY_LIST_SIZE 8 #define IPC_EMPTY_LIST_SIZE 8
...@@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, ...@@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
return 0; 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, static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header) struct skl_ipc_header header)
{ {
struct ipc_message *msg; struct ipc_message *msg;
u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
u64 *ipc_header = (u64 *)(&header); 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); msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
if (msg == NULL) { if (msg == NULL) {
...@@ -401,33 +421,39 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, ...@@ -401,33 +421,39 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
} }
/* first process the header */ /* first process the header */
switch (reply) { if (reply == IPC_GLB_REPLY_SUCCESS) {
case IPC_GLB_REPLY_SUCCESS:
dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary);
/* copy the rx data from the mailbox */ /* copy the rx data from the mailbox */
sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); 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_REPLY_OUT_OF_MEMORY: case IPC_GLB_LOAD_LIBRARY:
dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); skl->mod_load_complete = true;
msg->errno = -ENOMEM; skl->mod_load_status = true;
break; wake_up(&skl->mod_load_wait);
break;
case IPC_GLB_REPLY_BUSY:
dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary);
msg->errno = -EBUSY;
break;
default: default:
dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply); break;
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, "ipc FW reply: reply=%d\n", reply);
dev_err(ipc->dev, "FW Error Code: %u\n", dev_err(ipc->dev, "FW Error Code: %u\n",
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); 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); list_del(&msg->list);
...@@ -811,8 +837,8 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, ...@@ -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_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data,
(sizeof(u16) * module_cnt), NULL, 0); (sizeof(u16) * module_cnt));
if (ret < 0) if (ret < 0)
dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); 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, ...@@ -947,7 +973,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, 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}; struct skl_ipc_header header = {0};
u64 *ipc_header = (u64 *)(&header); u64 *ipc_header = (u64 *)(&header);
...@@ -959,7 +985,11 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, ...@@ -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_INSTANCE_ID(table_id);
header.primary |= IPC_MOD_ID(dma_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) if (ret < 0)
dev_err(ipc->dev, "ipc: load lib failed\n"); dev_err(ipc->dev, "ipc: load lib failed\n");
......
...@@ -69,6 +69,14 @@ struct skl_d0i3_data { ...@@ -69,6 +69,14 @@ struct skl_d0i3_data {
struct delayed_work work; 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 skl_sst {
struct device *dev; struct device *dev;
struct sst_dsp *dsp; struct sst_dsp *dsp;
...@@ -77,6 +85,11 @@ struct skl_sst { ...@@ -77,6 +85,11 @@ struct skl_sst {
wait_queue_head_t boot_wait; wait_queue_head_t boot_wait;
bool boot_complete; bool boot_complete;
/* module load */
wait_queue_head_t mod_load_wait;
bool mod_load_complete;
bool mod_load_status;
/* IPC messaging */ /* IPC messaging */
struct sst_generic_ipc ipc; struct sst_generic_ipc ipc;
...@@ -105,6 +118,8 @@ struct skl_sst { ...@@ -105,6 +118,8 @@ struct skl_sst {
void (*update_d0i3c)(struct device *dev, bool enable); void (*update_d0i3c)(struct device *dev, bool enable);
struct skl_d0i3_data d0i3; struct skl_d0i3_data d0i3;
const struct skl_dsp_ops *dsp_ops;
}; };
struct skl_ipc_init_instance_msg { struct skl_ipc_init_instance_msg {
...@@ -182,7 +197,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, ...@@ -182,7 +197,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
struct skl_ipc_large_config_msg *msg, u32 *param); struct skl_ipc_large_config_msg *msg, u32 *param);
int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, 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, int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
struct skl_ipc_d0ix_msg *msg); struct skl_ipc_d0ix_msg *msg);
......
...@@ -94,19 +94,6 @@ struct adsp_fw_hdr { ...@@ -94,19 +94,6 @@ struct adsp_fw_hdr {
u32 load_offset; u32 load_offset;
} __packed; } __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 { struct skl_ext_manifest_hdr {
u32 id; u32 id;
u32 len; u32 len;
...@@ -115,32 +102,6 @@ struct skl_ext_manifest_hdr { ...@@ -115,32 +102,6 @@ struct skl_ext_manifest_hdr {
u32 entries; 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) static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
{ {
int pvt_id; int pvt_id;
...@@ -222,21 +183,18 @@ static inline int skl_pvtid_128(struct uuid_module *module) ...@@ -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 * This generates a 128 bit private unique id for a module TYPE so that
* module instance is unique * 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; struct uuid_module *module;
uuid_le *uuid_mod;
int pvt_id; int pvt_id;
uuid_mod = (uuid_le *)mconfig->guid;
list_for_each_entry(module, &ctx->uuid_list, list) { list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
pvt_id = skl_pvtid_128(module); pvt_id = skl_pvtid_128(module);
if (pvt_id >= 0) { if (pvt_id >= 0) {
module->instance_id[pvt_id] = module->instance_id[pvt_id] = instance_id;
mconfig->id.instance_id;
return pvt_id; return pvt_id;
} }
} }
...@@ -254,23 +212,21 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); ...@@ -254,23 +212,21 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
* *
* This frees a 128 bit private unique id previously generated * 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; int i;
uuid_le *uuid_mod;
struct uuid_module *module; struct uuid_module *module;
uuid_mod = (uuid_le *)mconfig->guid;
list_for_each_entry(module, &ctx->uuid_list, list) { list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
if (mconfig->id.pvt_id != 0) if (*pvt_id != 0)
i = (mconfig->id.pvt_id) / 64; i = (*pvt_id) / 64;
else else
i = 0; i = 0;
module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id)); module->pvt_id[i] &= ~(1 << (*pvt_id));
mconfig->id.pvt_id = -1; *pvt_id = -1;
return 0; return 0;
} }
} }
...@@ -405,3 +361,83 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw) ...@@ -405,3 +361,83 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw)
return 0; 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, ...@@ -52,7 +52,8 @@ static int skl_transfer_firmware(struct sst_dsp *ctx,
{ {
int ret = 0; 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) if (ret < 0)
return ret; return ret;
...@@ -178,6 +179,18 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) ...@@ -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"); dev_err(ctx->dev, "unable to load firmware\n");
return ret; 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) ...@@ -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; 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) 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( ...@@ -323,27 +336,85 @@ static struct skl_module_table *skl_module_get_from_id(
return NULL; return NULL;
} }
static int skl_transfer_module(struct sst_dsp *ctx, static int skl_transfer_module(struct sst_dsp *ctx, const void *data,
struct skl_load_module_info *module) 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; 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, bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false);
module->fw->size); if (bytes_left < 0)
if (ret < 0) return bytes_left;
return ret;
ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, /* check is_module flag to load module or library */
(void *)&module->mod_id); if (is_module)
if (ret < 0) ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id);
dev_err(ctx->dev, "Failed to Load module: %d\n", ret); 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); ctx->cl_dev.ops.cl_stop_dma(ctx);
return ret; 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) static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
{ {
struct skl_module_table *module_entry = NULL; 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) ...@@ -365,7 +436,9 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
} }
if (!module_entry->usage_cnt) { 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) { if (ret < 0) {
dev_err(ctx->dev, "Failed to Load module\n"); dev_err(ctx->dev, "Failed to Load module\n");
return ret; return ret;
...@@ -388,6 +461,11 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) ...@@ -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); dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
return -EIO; 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, ret = skl_ipc_unload_modules(&skl->ipc,
SKL_NUM_MODULES, &mod_id); SKL_NUM_MODULES, &mod_id);
if (ret < 0) { if (ret < 0) {
...@@ -434,6 +512,16 @@ static struct skl_dsp_fw_ops skl_fw_ops = { ...@@ -434,6 +512,16 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
.unload_mod = skl_unload_module, .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 = { static struct sst_ops skl_ops = {
.irq_handler = skl_dsp_sst_interrupt, .irq_handler = skl_dsp_sst_interrupt,
.write = sst_shim32_write, .write = sst_shim32_write,
...@@ -455,45 +543,47 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -455,45 +543,47 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
struct sst_dsp *sst; struct sst_dsp *sst;
int ret; int ret;
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
if (skl == NULL) if (ret < 0) {
return -ENOMEM; dev_err(dev, "%s: no device\n", __func__);
return ret;
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;
} }
skl = *dsp;
sst = skl->dsp; sst = skl->dsp;
sst->fw_name = fw_name;
sst->addr.lpe = mmio_base; sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base; sst->addr.shim = mmio_base;
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); 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; sst->fw_ops = skl_fw_ops;
ret = skl_ipc_init(dev, skl); skl->cores.count = 2;
if (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; return ret;
}
skl->cores.count = 2; sst = (*dsp)->dsp;
skl->is_first_boot = true; sst->fw_ops = kbl_fw_ops;
if (dsp) return 0;
*dsp = skl;
return ret;
} }
EXPORT_SYMBOL_GPL(skl_sst_dsp_init); EXPORT_SYMBOL_GPL(kbl_sst_dsp_init);
int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
{ {
...@@ -507,6 +597,15 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) ...@@ -507,6 +597,15 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
} }
skl_dsp_init_core_state(sst); 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; ctx->is_first_boot = false;
return 0; return 0;
......
This diff is collapsed.
...@@ -257,6 +257,8 @@ struct skl_pipe_params { ...@@ -257,6 +257,8 @@ struct skl_pipe_params {
snd_pcm_format_t format; snd_pcm_format_t format;
int link_index; int link_index;
int stream; int stream;
unsigned int host_bps;
unsigned int link_bps;
}; };
struct skl_pipe { struct skl_pipe {
...@@ -334,17 +336,10 @@ struct skl_pipeline { ...@@ -334,17 +336,10 @@ struct skl_pipeline {
struct list_head node; struct list_head node;
}; };
#define SKL_LIB_NAME_LENGTH 128 struct skl_module_deferred_bind {
#define SKL_MAX_LIB 16 struct skl_module_cfg *src;
struct skl_module_cfg *dst;
struct skl_lib_info { struct list_head node;
char name[SKL_LIB_NAME_LENGTH];
const struct firmware *fw;
};
struct skl_manifest {
u32 lib_count;
struct skl_lib_info lib[SKL_MAX_LIB];
}; };
static inline struct skl *get_skl_ctx(struct device *dev) 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) ...@@ -512,7 +512,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
unsigned int res; unsigned int res = -1;
mutex_lock(&bus->cmd_mutex); mutex_lock(&bus->cmd_mutex);
snd_hdac_bus_send_cmd(bus, cmd); snd_hdac_bus_send_cmd(bus, cmd);
......
...@@ -77,6 +77,7 @@ struct skl { ...@@ -77,6 +77,7 @@ struct skl {
struct skl_dsp_resource resource; struct skl_dsp_resource resource;
struct list_head ppl_list; struct list_head ppl_list;
struct list_head bind_list;
const char *fw_name; const char *fw_name;
char tplg_name[64]; char tplg_name[64];
......
...@@ -1913,6 +1913,7 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, ...@@ -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); EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
#ifdef CONFIG_DMI
/* Trim special characters, and replace '-' with '_' since '-' is used to /* Trim special characters, and replace '-' with '_' since '-' is used to
* separate different DMI fields in the card long name. Only number and * separate different DMI fields in the card long name. Only number and
* alphabet characters and a few separator characters are kept. * 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) ...@@ -2044,6 +2045,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
#endif /* CONFIG_DMI */
static int snd_soc_instantiate_card(struct snd_soc_card *card) 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) ...@@ -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, snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
card->num_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), snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name); "%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment